Swift-核心之面向协议开发

Swift is a Protocol-Oriented Programming Language

Swift 是一门面向协议 (POP) 开发的语言

Swift 的核心是面向协议编程

WWDC 对 OOP 很好的诠释:

Protocol-Oriented Programming in Swift

POP 面向协议的编程

面向协议的编程的核心是抽象(Abstraction)和简化(Simplicity) 

协议的高级使用是协议的延展 

协议(protocol) + 结构体(struct) > 类(class)

面向对象面向协议比较

面向对象是一个很古老的软件开发模式,通过类来实现

面向协议是苹果在 swift 中主推的,通过协议和结构体,可以代替类

Swift 中的很多对象都改成了结构体和协议

并不是所有的类都可以被协议+结构体替代,但大多数是可以被替换的

面向协议使代码更加灵活,类似于组件化开发,符合工厂方法模式

实例比较:给一个类添加额外的方法

通过继承 

创建一个继承类的子类,在子类中添加方法,以后使用子类即可获取这个方法 

通过协议 

为这个方法定义一个协议,那个类需要实现这个方法,协议即可

使用继承的缺点:

通过继承添加的方法,不一定每个子类都会使用,使代码冗余

拥有太多的子类,使类冗余

对于父类的方法太过依赖,当父类的方法更改后,影响子类的重载方法

什么时候使用面向对象的类呢?

协议的高级使用是协议的延展以及和结构体配合

为协议添加属性, 属性为可读或可写

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 添加 一个数据为空视图

给 UIViewController 添加 一个遮挡提示视图

给 xib 添加一个快速获取示例方法

……(对控制器依赖比较小的视图等)

数据为空或者网络请求失败提示界面


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)        // 网络请求失败        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

/// 显示数据为空视图funcshowEmptyDataView(){addEmptyView(type: .emptyData, iconName:"emptyData", tipTitle:"数据为空")}/// 显示请求失败重新加载视图funcshowNetworkErrorReloadView(){addEmptyView(type: .networkError, iconName:"network_error", tipTitle:"网络出问题了,请检查网络", action: #selector(reloadData))}/// 移除空视图/重新加载视图funcremoveEmptyView(){hideEmptyView()}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

添加 guide 视图 到 window 上

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)    }}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,914评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,935评论 2 383
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,531评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,309评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,381评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,730评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,882评论 3 404
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,643评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,095评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,448评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,566评论 1 339
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,253评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,829评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,715评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,945评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,248评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,440评论 2 348

推荐阅读更多精彩内容