1. 程式人生 > >Swift 【基於 Swift 面向協議程式設計】

Swift 【基於 Swift 面向協議程式設計】

“我們如何在每天的開發過程中使用面向協議程式設計?Natasha 回答了這個問題,並專門針對 POP 的實際應用開發給出瞭解決方案,包含檢視,檢視控制器和網路的例項。關注本篇在 App Builders CH 大會上的演講,你將從面向物件程式設計轉向面向協議程式設計,這樣能使你的 Swift 程式設計更加清晰、更加易讀!

回到現實 – 我們假設 Swift 是最棒的程式語言。

今天,我將談談基於 Swift 的面向協議程式設計,我會側重在如何實現上。讓我們稱它 POP

基於 Swift 的面向協議程式設計 (00:37)

當 Swift 剛剛出現的時候,學習新東西都是令人興奮的。第一年,我很高興能學習它,我之前在 Swift 裡面使用我的 Objective C 程式碼 (有的時候用些值型別和更加有趣的東西)。但是直到去年的 WWDC,協議擴展出現了。

Dave Abrahams (讓你大開眼界的教授) 做了一次令人大開眼界的演講 “基於 Swift 的面向協議程式設計”。他聲稱 “Swift 就是一個面向協議的程式語言。” 如果你看看 Swift 的標準庫,那有超過 50 個協議。這就是這門語言的成形之處,它使用了許多的協議而且這也是我們想借鑑的地方。Dave 還給了一個如何使用協議來改進我們現有程式碼的例子。他使用了 drawables 的例子,比如正方形、三角形,圓形。使用協議能夠讓它們的實現變得特別令人吃驚。我是被震撼到了,但是對於我來說我卻無法直接使用,因為我在每天的工作中不使用 drawables。

回去以後,我冥思苦想,我該如何在每天的程式中使用面向協議程式設計呢。我們都有些從 Objective-C 和其他程式語言繼承下來的程式設計模式,所以從面向物件轉變到面向協議是一件很難的事情。

過去一年,我終於有機會實驗一下使用協議,我想分享些我改進程式碼的例子。因為這是實踐面向協議程式設計,我將會講到 View、 (UITable)ViewController 和 Networking。希望這能幫助你們考慮如何在你們的實際工作中使用協議。

讓我們假設你的產品經理過來和你說,“我們���在點選那個按鈕時候出現一個檢視,而且它會抖動。” 這是一個非常常見的動畫,比如,在你的密碼輸入框上 – 當用戶輸入���錯誤密碼時,它就會抖動。

我們常常都是從 Stack Overflow 開始的()。一些人可能已經有了 Swift 抖動物件的基礎程式碼。一些人甚至都有 Swift 的抖動物件的程式碼,我想都不用想,只要稍稍修改一下。最難的部分當然是架構:我在哪裡整合這些程式碼呢?

//  FoodImageView.swift

import UIKit

class FoodImageView: UIImageView {
    func shake() {
        let animation = CABasicAnimation(keyPath: "position")
        animation.duration = 0.05
        animation.repeatCount = 5
        animation.autoreverses = true
        animation.fromValue = NSValue(CGPoint: CGPointMake(self.center.x - 4.0, self.center.y))
        animation.toValue = NSValue(CGPoint: CGPointMake(self.center.x + 4.0, self.center.y))
        layer.addAnimation(animation, forKey: "position")
    }
}

我將建立一個 UIImageView 的子類,建立我的 FoodImageView 然後增加一個抖動的動畫:

//  ViewController.swift

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var foodImageView: FoodImageView!

    @IBAction func onShakeButtonTap(sender: AnyObject) {
        foodImageView.shake()
    }
}

在我的 view controller 裡面,在 interface builder 裡我連線我的 view,把它做為 FoodImageView 的子類,我有一個 shake 函式,然後 完成了!。10 分鐘我就完成了這個功能。我很開心,我的程式碼工作得很正常。

然後,你的產品經理過來說,”你需要在抖動檢視的時候抖動按鈕。” 然後我回去對按鈕做了同樣的事情。

//  ShakeableButton.swift

import UIKit

class ActionButton: UIButton {

    func shake() {
        let animation = CABasicAnimation(keyPath: "position")
        animation.duration = 0.05
        animation.repeatCount = 5
        animation.autoreverses = true
        animation.fromValue = NSValue(CGPoint: CGPointMake(self.center.x - 4.0, self.center.y))
        animation.toValue = NSValue(CGPoint: CGPointMake(self.center.x + 4.0, self.center.y))
        layer.addAnimation(animation, forKey: "position")
    }
}

Receive news and updates from Realm straight to your inbox

訂閱Comments 

子類,建立一個按鈕,增加一個 shake() 函式,和我的 ViewController。現在我能抖動我的 food 影象檢視和按鈕了,完成了。

//  ViewController.swift

class ViewController: UIViewController {

    @IBOutlet weak var foodImageView: FoodImageView!
    @IBOutlet weak var actionButton: ActionButton!

    @IBAction func onShakeButtonTap(sender: AnyObject) {
      foodImageView.shake()
      actionButton.shake()
    }
}

幸運的是,這會給你一個警告:我在兩個地方重複了抖動的程式碼。如果我想改變抖動的幅度,我需要改兩處程式碼,這很不好。

//  UIViewExtension.swift

import UIKit

extension UIView {

    func shake() {
        let animation = CABasicAnimation(keyPath: "position")
        animation.duration = 0.05
        animation.repeatCount = 5
        animation.autoreverses = true
        animation.fromValue = NSValue(CGPoint: CGPointMake(self.center.x - 4.0, self.center.y))
        animation.toValue = NSValue(CGPoint: CGPointMake(self.center.x + 4.0, self.center.y))
        layer.addAnimation(animation, forKey: "position")
    }
}

作為一個優秀的程式設計師,我們馬上會意識到這點,而且試圖重構。如果你以前使用過 Objective-C,我會建立一個 UIView 的類別,在 Swift 裡面,這就是擴充套件。

我能這樣做,因為 UIButton 和 UIImageView 都是 UI 檢視。我能擴充套件 UI 檢視而且增加一個 shake 函式。現在我仍然可以給我的按鈕和影象檢視都加上其他的邏輯,但是 shake 函式就到處都是了。

class FoodImageView: UIImageView {
    // other customization here
}

class ActionButton: UIButton {
    // other customization here
}

class ViewController: UIViewController {
    @IBOutlet weak var foodImageView: FoodImageView!
    @IBOutlet weak var actionButton: ActionButton!

    @IBAction func onShakeButtonTap(sender: AnyObject) {
        foodImageView.shake()
        actionButton.shake()
    }
}

馬上我們就能發現可讀性很差了。例如,對於 foodImageView 和 actionButton 來說,你看不出來任何抖動的意圖。整個類裡面沒有任何東西能告訴你它需要抖動。這不清楚,是因為別處會隨機存在一個抖動函式。

如果你常常為類別和 UI view 的擴充套件這樣做的話,你可能會有更好的辦法。這就是所謂的 科學怪人的垃圾地點,你增加了一個 shake 函式然後有人來和你說, “我想要一個可調暗的檢視”。然後你增加一個 dim 函式和其他別處隨機的呼叫函式。這樣,檔案會變得越來越長,不可讀,很難找到垃圾,因為這些隨機呼叫的事情都可以在 UI 視圖裡面完成,儘管有些時候也許只有一兩個地方需要這麼做。

意圖是什麼並不清晰。我們如何改變這點呢?

這是一次面向協議程式設計的演講,我們當然會用到協議。讓我們建立一個 Shakeable 的協議:

//  Shakeable.swift

import UIKit

protocol Shakeable { }

extension Shakeable where Self: UIView {

    func shake() {
        // implementation code
    }
}

在協議擴充套件的幫助下,你可以把它們限制在一個特定的類裡面。在這個例子裡面,我能抽出我的 shake 函式,然後用類別,我能說這是我們需要遵循的唯一的東西,只有 UI 檢視會有這個函式。

你仍然可以使用你原來想用的同樣強大的擴充套件功能,但是你有協議了。任何遵循協議的非檢視不會工作。只有檢視才能有這個 shake 的預設實現。

class FoodImageView: UIImageView, Shakeable {

}

class ActionButton: UIButton, Shakeable {

}

我們可以看到 FoodImageView 和 ActionButton 會遵循 Shakeable 協議。它們會有 shake 函式,現在的可讀性強多了 –- 我可以理解 shaking 是有意存在的。如果你在別處使用檢視,我需要想想,”在這也需要抖動嗎?”。它增強了可讀性,但是程式碼還是閉合的和可重用的。

假設我們想抖動和調暗檢視。我們會有另外一個協議,一個 Dimmable 協議,然後我們可以為了調暗做一個協議擴充套件。再強調一遍,通過看類的定義來知曉這個類的用途,這樣,意圖就會很明顯了。

class FoodImageView: UIImageView, Shakeable, Dimmable {

}

關於重構,當我們說 “我不想要抖動了”的時候,你只需要刪除相關的 Shakeable 協議就好了。

class FoodImageView: UIImageView, Dimmable {

}

現在它只能調暗了。插入是非常容易的,通過使用協議我們很容易獲得樂高似的架構。看看 這篇文章 如果你想學習使用協議的其他更強大的方式的話,試試建立一個有過渡效果的可調暗的檢視。

現在我們高興了,可以去吃 Pop-tarts 了。

(UITable)ViewControllers (10:09)

這是一個應用,Instagram 食物:它給你展示不同地點的美食照片。

// FoodLaLaViewController

override func viewDidLoad() {
    super.viewDidLoad()

    let foodCellNib = UINib(NibName: "FoodTableViewCell", bundle: nil)
    tableView.registerNib(foodCellNib,
                          forCellReuseIdentifier: "FoodTableViewCell")
}

這是一個 tableView。這是我們一直都會編寫的基礎程式碼。當檢視載入的時候,我們會從 Nib 中載入 cell;我們定製 NibName,然後我們使用一個 ReuseIdentifier 來註冊 Nib

let foodCellNib = UINib(NibName: String(FoodTableViewCell), bundle: nil)
tableView.registerNib(foodCellNib,
                      forCellReuseIdentifier: String(FoodTableViewCell))

不幸的是,因為 UIKit 建立方式的限制,我們不得不使用字串。我喜歡為我的 cell 使用相同的 identifiers 來作為 cell 的名字。

我們立刻就能看到低效的地方。如果你以前使用的是 Objective-C,我常常使用 NSString 作為類。在 Swift 裡面,你可以使用 String (稍好一點),相較 Objective-C 而言,我們已經足夠好了。我們常常就使用 String,但是如果一個沒有做過 iOS 開發的實習生來到我們的專案,這個函式對他來說就是天書。你會隨機的字串化一些名字,”為什麼你這樣做呢?”。同時,如果你不在 storyboard 裡指定 identifier 的話,現在它會 crashing 而且他們還不知道什麼原因。我們該如何改進呢?

protocol ReusableView
            
           

相關推薦

Swift 基於 Swift 面向協議程式設計

“我們如何在每天的開發過程中使用面向協議程式設計?Natasha 回答了這個問題,並專門針對 POP 的實際應用開發給出瞭解決方案,包含檢視,檢視控制器和網路的例項。關注本篇在 App Builders CH 大會上的演講,你將從面向物件程式設計轉向面向協議程式設計,這樣能使

基於VS2010的MFC程式設計四則運算計算器

平臺/工具:VS2010 目的:利用VS2010平臺建立一個MFC工程,實現四則運算計算器的程式編寫和介面設計 專案分析:實現 “+”“-”“”“/” 四則運算,需要幾個要素:運算子“+”“-”“”“/”、數字0~9,用於顯示參與運算的兩個數的編輯框、用於顯

Swift 中的面向協議程式設計:是否優於面向物件程式設計

作者:Andrew Jaffee,原文連結,原文日期:2018/03/28 譯者:陽仔;校對:numbbbbb,Lision;定稿:Forelax 在本文中,我們將深入討論 Swift 4 中的面向協議程式設計。這是一個系列兩篇文章中的第二篇。如果你還沒有讀過 前一篇介紹文章,請在繼續閱讀本文之前

Swift面向協議程式設計說開去

寫在最前 文章標題談到了面向協議程式設計(下文簡稱 POP),是因為前幾天閱讀了一篇講 Swift 中 POP 的文章。本文會以此為出發點,聊聊相關的概念,比如介面、mixin、組合模式、多繼承等,同時也會藉助各種語言中的例子來闡述我的思想。 那些老生常談的概念,相信每位讀者都耳熟能詳了,我當然不會無聊到浪

Swift面向協議程式設計(附程式碼)

什麼是swift協議? Protocol Swift標準庫中有50多個複雜不一的協議,幾乎所有的實際型別都是媽祖若干協議的。protocol是Swift語言的底座,語言的其他部分正是在這個底座上組織和建立起來的。這和我們熟知的面向物件的構建方式很不一樣。

swift面向協議程式設計

目前swift已經進化到4.0,蘋果也承諾3.0是最後一個破壞性升級的版本,也就是語法之類的基本穩定了,長遠來看,swift肯定是未來發展的主流方向。相比較之前OC中面向物件變成,swift中提倡的是面向協議程式設計。swift中很多語法規則也體現了蘋果的這一傾向。有點玄乎,

深入理解Swift 面向協議程式設計

文章標題談到了面向協議程式設計(下文簡稱 POP),是因為前幾天閱讀了一篇講 Swift 中 POP 的文章。本文會以此為出發點,聊聊相關的概念,比如介面、mixin、組合模式、多繼承等,同時也會藉助各種語言中的例子來闡述我的思想。 那些老生常談的概念,相信每位讀者都耳熟能

iOS開發:Swift面向協議程式設計初探

最近有時間,挑了幾個今年WWDC中比較感興趣的Session視訊來學習,今天就抽時間整理一下關於Swift 2.0中一個比較新的概念面向協議程式設計。 相關的Session視訊連結如下: 寫在前面 面向協議程式設計是什麼? 你可能聽

Java TCP/IP Socket程式設計----傳送和接收資料----構建和解析協議訊息

--------筆記來自於書籍《Java TCP/IP Socket程式設計》。 簡介 使用套接字時,通常要麼是需要同時建立通訊通道兩端的程式,要麼實現一個給定的協議進行通訊。如果知道通訊雙方都使用java實現,且擁有對協議的完全控制權,那麼就可以使用Java的內建工具如Serialiabl

SpringAOP面向切面程式設計AOP的註解獲取引數和修改引數

Spring的AOP功能就是面向切面程式設計.我們從Spring容器取出的值,就是已經被重新包裝過代理物件 概念 通知: 要切入的內容 切點: 要切入的地方 切面織入: 將切面織入類的方法中,切面=通知+切點 通知的類 在該類中宣告各自通知,每個

iOS重構之面向協議程式設計實踐

iOS重構之面向協議程式設計實踐 最近一段時間都在進行iOS客戶端的重構,參考了許多iOS重構方面的資料,在重構的過程中也遇到一些困難,同時總結了不少經驗,在這裡和大家分享一下。這將會是一個系列的文章,每一篇文章都會從一個具體的、普遍性的問題出發,然後分析和解決這個問題。 插一句,軟體開發本身是一件工程化

Java TCP/IP Socket程式設計----綜述

    【Java TCP/IP Socket程式設計】的筆記系列內容完全來自於《Java TCP/IP Socket程式設計》一書,本書的作者是neth L. Calvert / Michael J. Donahoo,很多Java程式使用的框架會涉及網路程式設計的知識,比如Du

Java TCP/IP Socket程式設計----深入剖析----TCP套接字生命週期

目錄   簡介 TCP連線 關閉TCP連線 解調多路複用 --------筆記來自於書籍《Java TCP/IP Socket程式設計》 簡介     新的Socket例項建立後(無論是通過公有的建構函式,或通過呼叫ServerSoc

Java TCP/IP Socket程式設計----深入剖析----TCP資料傳輸中的死鎖和效能

目錄   死鎖問題 資料傳輸效能 案例 --------筆記來自於書籍《Java TCP/IP Socket程式設計》 死鎖問題 在TCP資料傳輸底層實現中(詳細參見https://blog.csdn.net/lili13897741554/article/

Java TCP/IP Socket程式設計----深入剖析----TCP資料傳輸底層實現

目錄   套接字底層資料結構 TCP資料傳輸底層實現 案例 --------筆記來自於書籍《Java TCP/IP Socket程式設計》 套接字底層資料結構     要熟悉掌握網路程式設計,就需要理解套接字的具體實現所關聯的資料結構和底

Java TCP/IP Socket程式設計----NIO----TCP通道

NIO介紹 基本Java套接字對於小規模系統可以很好執行,涉及同時有上千個客戶端,就會出現問題,其中一客戶一執行緒的方式線上程的建立,維護和切換需要系統開銷較大,而使用執行緒池的方式雖然節省了一定的系統開銷,但是對於連線生存期比較長的協議,執行緒池的大小限制了系統可以同時服務的客戶端總數。隨著執

Java TCP/IP Socket程式設計----進階----注意點

1.廣播和多播:TCP套接字中客戶端只能接收和傳送指定伺服器端過來的資料,這種一對一的通訊方式叫單播,而UDP套接字可以容許一個傳送端和多個接收端情況,一對多的型別有:廣播和多播。       1)廣播:本地網路中所有的主機都會接收到一份資料副本。IPv4廣播地址(

Java TCP/IP Socket程式設計----進階----多工處理

簡介  基本的TCP相應伺服器是一次只能處理一個客戶端請求,無法處理同時多個客戶端請求,Java中多執行緒技術解決這一問題。多執行緒有兩種方式:一是一客戶一執行緒;二是執行緒池; 1)一客戶一執行緒:即為每個連線建立一個執行緒來處理,伺服器端會迴圈執行,監聽指定埠的連線,反覆接收來

Java TCP/IP Socket程式設計----傳送和接收資料----訊息成幀與解析

目錄   簡介 成幀與解析 成幀技術案例 簡介 在程式中使用套接字向其他程式提供資訊或者使用其他程式提供的資訊,這就需要任何需要交換資訊的程式間在資訊編碼方式上達成共識(包含了資訊交換的形式和意義),稱為協議,用來實現特定的應用程式的協議叫應用程式協議。大部分應

Java TCP/IP Socket程式設計----套接字----UDP Socket

目錄   簡介 UDP通訊 UDP通訊案例 UDP套接字注意點 簡介 UDP是面向無連線的協議,在資料傳輸時,資料的傳送端和接收端不建立邏輯上的連線。當一臺計算機向另外一臺計算機發送資料時,傳送端不會確認接收端是否存在,同樣接收端接收到資料時,也不會發送反饋