Swift is a Protocol-Oriented Programming Language
Swift 是一門面向協(xié)議 (POP) 開發(fā)的語言
WWDC 對 OOP 很好的詮釋:
Protocol-Oriented Programming in Swift
面向協(xié)議的編程的核心是抽象(Abstraction)和簡化(Simplicity)?
協(xié)議的高級使用是協(xié)議的延展?
協(xié)議(protocol) + 結(jié)構(gòu)體(struct) > 類(class)
面向?qū)ο笫且粋€很古老的軟件開發(fā)模式梦裂,通過類來實現(xiàn)
面向協(xié)議是蘋果在 swift 中主推的融击,通過協(xié)議和結(jié)構(gòu)體,可以代替類
Swift 中的很多對象都改成了結(jié)構(gòu)體和協(xié)議
并不是所有的類都可以被協(xié)議+結(jié)構(gòu)體替代,但大多數(shù)是可以被替換的
面向協(xié)議使代碼更加靈活,類似于組件化開發(fā),符合工廠方法模式
通過繼承?
創(chuàng)建一個繼承類的子類恰梢,在子類中添加方法,以后使用子類即可獲取這個方法?
通過協(xié)議?
為這個方法定義一個協(xié)議梗掰,那個類需要實現(xiàn)這個方法嵌言,協(xié)議即可
通過繼承添加的方法,不一定每個子類都會使用及穗,使代碼冗余
擁有太多的子類摧茴,使類冗余
對于父類的方法太過依賴,當父類的方法更改后埂陆,影響子類的重載方法
…
協(xié)議的高級使用是協(xié)議的延展以及和結(jié)構(gòu)體配合
protocol MessageModelProtocol {varname: String {getset}varage:? Int {setget}}
1
2
3
4
struct MessageModel: MessageModelProtocol {varname: String =""varage: Int =0varisMale: Bool =falseinit(with dict: [String: Any]) {self.name = (dict["name"]as? String) ??""self.age = (dict["age"]as? Int) ??0self.isMale = (dict["isMale"]as? Bool) ??false}}
1
2
3
4
5
6
7
8
9
10
11
12
extensionMessageModelProtocol{? ? mutating func test() {self.name ="Hello iPhone 8"}}
1
2
3
4
5
protocol DemoMessageModelProtocol: MessageModelProtocol {? ? vardate:Date{setget}}
1
2
3
4
給 UIViewController 添加 一個數(shù)據(jù)為空視圖
給 UIViewController 添加 一個遮擋提示視圖
給 xib 添加一個快速獲取示例方法
……(對控制器依賴比較小的視圖等)
數(shù)據(jù)為空或者網(wǎng)絡請求失敗提示界面
import UIKitenum EmptyType {? ? case emptyData? ? case networkError}protocol EmptyDataSetProtocol { }extension EmptyDataSetProtocol where Self : UIViewController {? ? func addEmptyView(type: EmptyType? =.emptyData, iconName: String, tipTitle: String, action: Selector? = nil) {? ? ? ? let emptyView = UIView(frame: view.bounds)? ? ? ? emptyView.backgroundColor= UIColor.whiteemptyView.tag=1024view.addSubview(emptyView)? ? ? ? let icomViewW: CGFloat =100let imageView = UIImageView(image: UIImage(named: iconName))? ? ? ? imageView.frame.size= imageView.image?.size?? CGSize(width: icomViewW, height: icomViewW)? ? ? ? imageView.contentMode=.centerimageView.center= CGPoint(x: emptyView.center.x,y: emptyView.center.y-100)? ? ? ? emptyView.addSubview(imageView)? ? ? ? let tipLabel = UILabel()? ? ? ? let margin: CGFloat =20tipLabel.numberOfLines=0tipLabel.font= UIFont.systemFont(ofSize:14)? ? ? ? tipLabel.textColor= UIColor.lightGrayif tipTitle.contains("\n") {? ? ? ? ? ? let style = NSMutableParagraphStyle()? ? ? ? ? ? style.lineSpacing=5// 設置行間距? ? ? ? ? ? style.alignment=.center// 文字居中? ? ? ? ? ? let tipString = NSAttributedString(string: tipTitle, attributes: [NSParagraphStyleAttributeName: style])? ? ? ? ? ? tipLabel.attributedText= tipString? ? ? ? } else {? ? ? ? ? ? tipLabel.text= tipTitle? ? ? ? }? ? ? ? tipLabel.adjustsFontSizeToFitWidth= true? ? ? ? tipLabel.textAlignment=.centertipLabel.sizeToFit()? ? ? ? tipLabel.frame= CGRect(x: margin,y: imageView.frame.maxY+ margin, width: UIScreen.main.bounds.width- margin*2, height: tipLabel.bounds.height)? ? ? ? emptyView.addSubview(tipLabel)? ? ? ? // 網(wǎng)絡請求失敗? ? ? ? if type ==.networkError{? ? ? ? ? ? let reloadButton = UIButton(type:.system)? ? ? ? ? ? reloadButton.frame.size= CGSize(width:100, height:36)? ? ? ? ? ? reloadButton.center= CGPoint(x: emptyView.center.x,y: tipLabel.frame.maxY+ margin*2)? ? ? ? ? ? reloadButton.backgroundColor= UIColor(red:255/255.0, green:42/255.0, blue:102/255.0, alpha:1.0)? ? ? ? ? ? reloadButton.layer.cornerRadius=18reloadButton.layer.masksToBounds= true? ? ? ? ? ? reloadButton.setTitle("重新加載", for:.normal)? ? ? ? ? ? reloadButton.setTitleColor(UIColor.white, for:.normal)? ? ? ? ? ? reloadButton.titleLabel?.font= UIFont.systemFont(ofSize:16)? ? ? ? ? ? reloadButton.addTarget(self, action: action!, for:.touchUpInside)? ? ? ? ? ? emptyView.addSubview(reloadButton)? ? ? ? }? ? }? ? func hideEmptyView() {? ? ? ? view.subviews.filter({ $0.tag ==1024}).first?.removeFromSuperview()? ? }}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
class ViewController: UIViewController, EmptyDataSetProtocol {...}
1
/// 顯示數(shù)據(jù)為空視圖funcshowEmptyDataView(){addEmptyView(type: .emptyData, iconName:"emptyData", tipTitle:"數(shù)據(jù)為空")}/// 顯示請求失敗重新加載視圖funcshowNetworkErrorReloadView(){addEmptyView(type: .networkError, iconName:"network_error", tipTitle:"網(wǎng)絡出問題了苛白,請檢查網(wǎng)絡", action: #selector(reloadData))}/// 移除空視圖/重新加載視圖funcremoveEmptyView(){hideEmptyView()}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import UIKitprotocol GuideViewProtocol { }extension GuideViewProtocol where Self : UIViewController {? ? func showGuideView(with title: String, imageName: String, buttonName: String, sureAction: Selector, cancelAction: Selector) {? ? ? ? let kScreenW: CGFloat = UIScreen.main.bounds.widthlet kMargine: CGFloat =30let backgroundView = UIView(frame: UIScreen.main.bounds)? ? ? ? backgroundView.backgroundColor= UIColor.black.withAlphaComponent(0.3)? ? ? ? backgroundView.tag=1024UIApplication.shared.keyWindow?.addSubview(backgroundView)? ? ? ? let containerView = UIView()? ? ? ? containerView.frame.size= CGSize(width: kScreenW-kMargine*2, height: (kScreenW-kMargine*2) +20)? ? ? ? containerView.backgroundColor= UIColor.whitecontainerView.center= backgroundView.centercontainerView.layer.cornerRadius=15backgroundView.addSubview(containerView)? ? ? ? let tipLabel = UILabel(frame: CGRect(x: kMargine,y:30, width: containerView.bounds.width-kMargine*2, height: kMargine))? ? ? ? tipLabel.font= UIFont.systemFont(ofSize:20)? ? ? ? tipLabel.textColor= UIColor.redtipLabel.textAlignment=.centertipLabel.text= title? ? ? ? containerView.addSubview(tipLabel)? ? ? ? let sureButton = UIButton(type:.system)? ? ? ? sureButton.frame.size= CGSize(width:200, height:30)? ? ? ? sureButton.setTitle(buttonName, for:.normal)? ? ? ? sureButton.setTitleColor(UIColor.white, for:.normal)? ? ? ? sureButton.backgroundColor= UIColor.redsureButton.titleLabel?.font= UIFont.systemFont(ofSize:18)? ? ? ? sureButton.frame.origin.x= (containerView.bounds.width- sureButton.bounds.width)*0.5sureButton.center.y= containerView.bounds.height-20- sureButton.bounds.heightsureButton.layer.cornerRadius=15sureButton.addTarget(self, action: sureAction, for:.touchUpInside)? ? ? ? containerView.addSubview(sureButton)? ? ? ? let centerImageView = UIImageView(image: UIImage(named: imageName))? ? ? ? centerImageView.contentMode=.scaleAspectFitcenterImageView.frame= CGRect(x:30,y: tipLabel.frame.maxY+20, width: containerView.bounds.width-60, height: sureButton.frame.minY- tipLabel.frame.maxY-40)? ? ? ? containerView.addSubview(centerImageView)? ? ? ? let cancelButton = UIButton(type:.custom)? ? ? ? cancelButton.setBackgroundImage(UIImage(named:"cancelButton"), for:.normal)? ? ? ? cancelButton.frame.size= cancelButton.currentBackgroundImage?.size?? CGSize.zerocancelButton.center.x= UIScreen.main.bounds.width*0.5cancelButton.center.y= containerView.frame.maxY+50cancelButton.addTarget(self, action: cancelAction, for:.touchUpInside)? ? ? ? backgroundView.addSubview(cancelButton)? ? }? ? func hideGuideView() {? ? ? ? UIView.animate(withDuration:0.25) {? ? ? ? ? ? UIApplication.shared.keyWindow?.subviews.filter({ $0.tag ==1024}).first?.removeFromSuperview()? ? ? ? }? ? }}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
class ViewController: UIViewController, GuideViewProtocol {...}
1
/// 添加指示視圖到當前視圖的 window 上funcaddGuideView(){showGuideView(with:"您有VIP禮包待領取", imageName:"vip_image", buttonName:"立即領取", sureAction: #selector(sureAction), cancelAction: #selector(removeGuideView))}/// 提示視圖上按鈕的點擊事件funcsureAction(){show(FirstViewController(), sender: nil)hideGuideView()}/// 移除指示視圖funcremoveGuideView(){hideGuideView()}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
protocol LeftBarButtonChangeable { }extension LeftBarButtonChangeable where Self :UIViewController{? ? func changeLeftBarButton(_ imageName: String, action: Selector ) {? ? ? ? let itemButton =UIButton(type:.custom)? ? ? ? itemButton.setImage(UIImage(named: imageName),for:.normal)? ? ? ? itemButton.sizeToFit()? ? ? ? itemButton.addTarget(self, action: action,for:.touchUpInside)self.navigationItem.leftBarButtonItem=UIBarButtonItem(customView: itemButton)? ? }}
1
2
3
4
5
6
7
8
9
10
11
12
13
classViewController:UIViewController,LeftBarButtonChangeable{override func viewDidLoad() {super.viewDidLoad()? ? ? ? changeLeftBarButton("back_image",action:#selector(backAction))}? ? func backAction() {? ? ? ? navigationController?.popViewController(animated:true)? ? }}