成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Swift面向協議編程(POP)的一些Tips

移動開發
協議最常見的用法莫過于進行代理傳值,這就是委托模式。常用的應用場景有:controller中自定義了一個view,view中又添加了一個自定義view。在自定義的view中如果有些函數或者屬性需要到controller中去調用,委托模式的做法就是規定一個協議,讓controller去遵守一個協議并提供實現。

一、委托模式

1、使用過程

協議最常見的用法莫過于進行代理傳值,這就是委托模式。常用的應用場景有:controller中自定義了一個view,view中又添加了一個自定義view。在自定義的view中如果有些函數或者屬性需要到controller中去調用,委托模式的做法就是規定一個協議,讓controller去遵守一個協議并提供實現,那么在自定義view中就能使用協議中的方法。

Swift面向協議編程(POP)的一些Tips

舉個例子,現在想在一個controller中添加一個自定義view,可以實現點擊view中按鈕更改controller中label的值。簡單的代碼如下:

自定義view 

  1. //SelectTabbar.swift 
  2. @objc protocol SelectTabbarDelegate { 
  3.     func changeLabel(_ str: String) 
  4.  
  1. //SelectTabbar.swift 
  2.  class SelectTabbar: UIView { 
  3.     var keywords : [String]? 
  4.     var buttons : [UIButton]? 
  5.     weak public var delegate : SelectTabbarDelegate? 
  6.       
  7.     init(frame: CGRect,keywords:[String]) { 
  8.         super.init(frame: frame) 
  9.         self.keywords = keywords 
  10.         renderView() 
  11.     } 
  12.       
  13.     required init?(coder aDecoder: NSCoder) { 
  14.         fatalError("init(coder:) has not been implemented"
  15.     } 
  16.       
  17.     override func layoutSubviews() { 
  18.         super.layoutSubviews() 
  19.     } 
  20.       
  21.     private func renderView(){ 
  22.         buttons = keywords?.enumerated().map({ (index,key) ->UIButton in 
  23.             let buttonWidth = kScreenWidth/CGFloat((keywords?.count)!) 
  24.             let button = UIButton.init(frame: CGRect.init(x: CGFloat(index)*buttonWidth, y: 0, width: buttonWidth, height: 50)) 
  25.             button.setTitle(keyfor: .normal) 
  26.             button.setTitleColor(UIColor.blue, for: .normal) 
  27.             button.backgroundColor = UIColor.gray 
  28.             button.tag = index 
  29.             button.addTarget(self, action: #selector(tapButton(sender:)), for: .touchUpInside) 
  30.             addSubview(button) 
  31.             return button 
  32.         }) 
  33.     } 
  34.       
  35.     @objc func tapButton(sender: UIButton){ 
  36.         delegate?.changeLabel(keywords![sender.tag]) 
  37.     } 
  38.       

controller: 

  1. class TestViewController: UIViewController,SelectTabbarDelegate { 
  2.     lazy var label : UILabel = { 
  3.         var label = UILabel(frame: CGRect.init(x: 50, y: 200, width: 100, height: 30)) 
  4.         label.text = labelStr 
  5.         label.backgroundColor = UIColor.red 
  6.         return label 
  7.     }() 
  8.       
  9.     private var labelStr : String? { 
  10.         didSet{ 
  11.             label.text = labelStr 
  12.         } 
  13.     } 
  14.       
  15.     override func viewDidLoad() { 
  16.         super.viewDidLoad() 
  17.         view.backgroundColor = .white 
  18.         view.addSubview(label) 
  19.         setupSelectTabbar() 
  20.     } 
  21.       
  22.     func setupSelectTabbar(){ 
  23.         let selectTabbar = SelectTabbar(frame: CGRect.init(x: 0, y: kNavigationHeightAndStatuBarHeight, width: kScreenWidth, height: 50),keywords:["aa","bb"]) 
  24.         selectTabbar.delegate = self 
  25.         view.addSubview(selectTabbar) 
  26.     } 
  27.     func changeLabel(_ str: String) { 
  28.         labelStr = str 
  29.     } 
  30.       

這樣就能比較清楚的表明自己的邏輯。否則,如果要在view操作controller的內容,則需要在外部操作controller的實例,這就造成一個問題,就是無法操作實例中的私有屬性和私有方法(雖然iOS是一門動態語言,不存在絕對的私有,但是誰會去一直去使用runtime來進行操作呢)。

2、注意點

在 ARC 中,對于一般的 delegate,我們會在聲明中將其指定為 weak,在這個 delegate 實際的對象被釋放的時候,會被重置回 nil。這可以保證即使 delegate 已經不存在時,我們也不會由于訪問到已被回收的內存而導致崩潰。ARC 的這個特性杜絕了 Cocoa 開發中一種非常常見的崩潰錯誤,說是救萬千程序員于水火之中也毫不為過。

在 Swift 中我們當然也會希望這么做。但是當我們嘗試書寫這樣的代碼的時候,編譯器不會讓我們通過:

  1. 'weak' cannot be applied to non-class type 

原因:這是因為 Swift 的 protocol 是可以被除了 class 以外的其他類型遵守的,而對于像 struct 或是 enum 這樣的類型,本身就不通過引用計數來管理內存,所以也不可能用 weak 這樣的 ARC 的概念來進行修飾。

兩種解決方法:

  1. 使用@objc
  2. 聲明類類型專屬協議。通過添加 class 關鍵字來限制協議只能被類類型遵循,而結構體或枚舉不能遵循該協議。class 關鍵字必須***個出現在協議的繼承列表中,在其他繼承的協議之前
  • protocol SelectTabbarDelegate : class

二、AOP編程思想的運用

首先我們理解下AOP的含義。

  • In computing, aspect-oriented programming (AOP) is a programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns. It does so by adding additional behavior to existing code (an advice) without modifying the code itself, instead separately specifying which code is modified via a “pointcut” specification, such as “log all function calls when the function’s name begins with ‘set’”. This allows behaviors that are not central to the business logic (such as logging) to be added to a program without cluttering the code, core to the functionality. AOP forms a basis for aspect-oriented software development.

在swift簡單來說,就是利用協議去切入某些代碼中,將額外的功能單獨出來而不產生耦合,可以將這些與主邏輯關系不大的代碼統一放到一起。

常用的場景:日志記錄,性能統計,安全控制,事務處理,異常處理等等。

接上面的例子,我們需要在打開TestViewController的時候統計一次,點擊兩個按鈕的時候也進行統計,統計的內容由identifer進行區分。

我們先建立一個Statistician.swift 來存放我們的統計邏輯。(模擬實現)

申明一個StatisticianProtocal協議并提供他的默認實現。 

  1. import Foundation 
  2. enum LogIdentifer:String { 
  3.     case button1 = "button1" 
  4.     case button2 = "button2" 
  5.     case testViewController = "testViewController" 
  6.   
  7. protocol StatisticianProtocal { 
  8.     func statisticianLog(fromClass:AnyObject, identifer:LogIdentifer) 
  9.     func statisticianUpload(fromClass:AnyObject, identifer:LogIdentifer) 
  10.     //用一個尾隨閉包來擴展功能 
  11.     func statisticianExtension(fromClass:AnyObject, identifer:LogIdentifer, extra:()->()) 
  12.   
  13. extension StatisticianProtocal{ 
  14.     func statisticianLog(fromClass:AnyObject, identifer:LogIdentifer) { 
  15.         print("statisticianLog--class:\(fromClass) from:\(identifer.rawValue)"
  16.     } 
  17.       
  18.     func statisticianUpload(fromClass:AnyObject, identifer:LogIdentifer) { 
  19.         print("statisticianUpload--class:\(fromClass) from:\(identifer.rawValue)"
  20.     } 
  21.       
  22.     func statisticianExtension(fromClass:AnyObject, identifer:LogIdentifer, extra:()->()){ 
  23.         extra() 
  24.     } 
  25.   
  26. class Statistician: NSObject { 
  27.   

接下來在任何需要統計的類里面,我們讓這個類去遵守這個協議,然后在需要的地方調用協議中的方法即可。如果在某個特定的類中需要調用的方法略有不同,重寫協議中的方法即可。 

  1. class SelectTabbar: UIView,StatisticianProtocal { 
  2.     var keywords : [String]? 
  3.     var buttons : [UIButton]? 
  4.     weak public var delegate : SelectTabbarDelegate? 
  5.       
  6.     init(frame: CGRect,keywords:[String]) { 
  7.         super.init(frame: frame) 
  8.         self.keywords = keywords 
  9.         renderView() 
  10.         //進行一次統計 
  11.         operateStatistician(identifer: .testViewController) 
  12.     } 
  13.       
  14.     required init?(coder aDecoder: NSCoder) { 
  15.         fatalError("init(coder:) has not been implemented"
  16.     } 
  17.       
  18.       
  19.     override func layoutSubviews() { 
  20.         super.layoutSubviews() 
  21.     } 
  22.       
  23.     private func renderView(){ 
  24.         buttons = keywords?.enumerated().map({ (index,key) ->UIButton in 
  25.             let buttonWidth = kScreenWidth/CGFloat((keywords?.count)!) 
  26.             let button = UIButton.init(frame: CGRect.init(x: CGFloat(index)*buttonWidth, y: 0, width: buttonWidth, height: 50)) 
  27.             button.setTitle(keyfor: .normal) 
  28.             button.setTitleColor(UIColor.blue, for: .normal) 
  29.             button.backgroundColor = UIColor.gray 
  30.             button.tag = index 
  31.             button.addTarget(self, action: #selector(tapButton(sender:)), for: .touchUpInside) 
  32.             addSubview(button) 
  33.             return button 
  34.         }) 
  35.     } 
  36.       
  37.     @objc func tapButton(sender: UIButton){ 
  38.         //進行一次統計 
  39.         switch sender.tag { 
  40.           case 0:operateStatistician(identifer: .button1) 
  41.           default:operateStatistician(identifer: .button2) 
  42.         } 
  43.         delegate?.changeLabel(keywords![sender.tag]) 
  44.     } 
  45.       
  46.     func operateStatistician(identifer:LogIdentifer){ 
  47.         statisticianLog(fromClass: self, identifer: identifer) 
  48.         statisticianUpload(fromClass: self, identifer: identifer) 
  49.         statisticianExtension(fromClass: self, identifer: identifer) { 
  50.             print("extra: in SelectTabbar class"
  51.         } 
  52.     } 
  53.       

以上代碼實現了三處統計的邏輯,而不用把統計的邏輯寫入controller文件中,降低了功能上的耦合度。

三、用來代替extension,增強代碼可讀性

使用擴展,可以很方便的為一些繼承它的子類增添一些函數。這就帶來一個問題,就是所有的子類都擁有了這個方法,但是方法的本身可能不明確,或者是只是想讓少數子類來使用這個方法。這時候可以使用協議來代替extension。 

  1. //定義了一個Shakable協議,遵守這個協議的類即可使用里面的方法,并為該方法提供一個默認的實現 
  2. //where Self:UIView表明了只有uiview的子類可以遵守這個協議 
  3. protocol Shakable { 
  4.     func shakeView() 
  5.   
  6. extension Shakable where Self:UIView{ 
  7.     func shakeView(){ 
  8.         print(Self.self) 
  9.     } 

這時候可以讓某個子類來遵守協議。例如剛才上面的例子。

  1. class SelectTabbar: UIView,Shakable 

如果不在類中重新實現這個方法,則可以實現默認的方法。這個意思表明,SelectTabbar類的子類是遵守Shakable協議的,間接等于SelectTabbar():Shakable?。這樣我們就可以愉快的讓SelectTabbar對象去使用這個方法。(Self關鍵字只能用在協議或者類中,表示當前類,可作為返回值使用)。

一旦不想讓某個子類使用shakeView()方法,很簡單,只要把class SelectTabbar: UIView,Shakable中的Shakable協議干掉即可。

其他實踐:

利用AOP去分離tableview的數據源和事件源的方法,可以單獨處理里面的邏輯,使tableview的代理方法不顯得那么冗余。

總結

關于協議,還有很多種用法。以上是目前比較常用的場景。日后開發中如果發現協議在其他地方中有更好的應該,將會更新本文

 

責任編輯:未麗燕 來源: peipeiblog
相關推薦

2023-10-09 08:14:10

Helm管理應用

2013-07-02 09:43:02

編程策略

2013-07-02 10:18:20

編程編程策略

2010-06-09 17:13:12

IPv6協議路由協議

2021-10-13 07:48:23

Options模式編程

2021-04-09 10:26:43

Python編程技術

2010-08-05 13:54:36

NFS協議

2011-08-31 10:54:25

Java性能

2018-06-08 08:50:35

編程語言并發編程

2011-09-13 09:41:59

Python

2016-12-12 15:22:41

編程

2012-02-16 08:19:03

2012-04-05 13:24:30

2022-07-30 23:41:53

面向過程面向對象面向協議編程

2010-09-17 15:41:46

網絡協議分析軟件

2009-11-23 13:44:33

PHP5面向對象

2015-08-04 08:56:14

swift子類

2015-09-15 10:40:41

Swift2.0MVVM

2014-12-26 09:56:50

編程語言

2015-03-30 11:21:27

編程編程反思
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩欧美网 | av影音资源 | 国产精品久久久久aaaa九色 | 日韩www视频 | 国产高清在线观看 | 在线免费视频一区 | 久久精品一区二区视频 | 亚洲免费精品 | 国产精品一区一区 | 亚洲一区视频在线播放 | 正在播放国产精品 | 欧美日韩18 | 亚洲h在线观看 | 亚洲美女视频 | 亚洲国产精品久久久久婷婷老年 | 国产乱码精品一区二区三区五月婷 | 欧美一级久久 | 久久精品久久久 | 黑人精品欧美一区二区蜜桃 | 色婷婷综合网 | 亚洲视频三区 | 毛色毛片免费看 | 一区二区三区视频在线观看 | 蜜桃传媒一区二区 | 天堂在线免费视频 | 日韩精品一区二区三区在线播放 | 欧美亚洲另类在线 | 欧美一区二区在线免费观看 | 久色视频在线 | 欧美精品一区三区 | 亚洲视频在线看 | 国产亚洲精品精品国产亚洲综合 | 久久久久99| 午夜免费成人 | 久久久久成人精品 | 国产日韩精品一区 | 久久久久久亚洲精品 | 在线观看免费av网 | 精品国产乱码久久久久久丨区2区 | 久久久美女 | 亚洲激情在线观看 |