Swift-核心之面向協(xié)議開發(fā)

Swift is a Protocol-Oriented Programming Language

Swift 是一門面向協(xié)議 (POP) 開發(fā)的語言

Swift 的核心是面向協(xié)議編程

WWDC 對 OOP 很好的詮釋:

Protocol-Oriented Programming in Swift

POP 面向協(xié)議的編程

面向協(xié)議的編程的核心是抽象(Abstraction)和簡化(Simplicity)?

協(xié)議的高級使用是協(xié)議的延展?

協(xié)議(protocol) + 結(jié)構(gòu)體(struct) > 類(class)

面向?qū)ο?/b>與面向協(xié)議比較

面向?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é)議即可

使用繼承的缺點:

通過繼承添加的方法,不一定每個子類都會使用及穗,使代碼冗余

擁有太多的子類摧茴,使類冗余

對于父類的方法太過依賴,當父類的方法更改后埂陆,影響子類的重載方法

什么時候使用面向?qū)ο蟮念惸兀?/a>

協(xié)議的高級使用是協(xié)議的延展以及和結(jié)構(gòu)體配合

為協(xié)議添加屬性, 屬性為可讀或可寫

protocol MessageModelProtocol {varname: String {getset}varage:? Int {setget}}

1

2

3

4

定義一個接受協(xié)議的結(jié)構(gòu)體

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

對協(xié)議進行延展

extensionMessageModelProtocol{? ? mutating func test() {self.name ="Hello iPhone 8"}}

1

2

3

4

5

協(xié)議的協(xié)議

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

添加 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

修改導航欄左側(cè)按鈕

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

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市焚虱,隨后出現(xiàn)的幾起案子购裙,更是在濱河造成了極大的恐慌,老刑警劉巖鹃栽,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件躏率,死亡現(xiàn)場離奇詭異,居然都是意外死亡民鼓,警方通過查閱死者的電腦和手機薇芝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來丰嘉,“玉大人夯到,你說我怎么就攤上這事∫鳎” “怎么了耍贾?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長克滴。 經(jīng)常有香客問我逼争,道長,這世上最難降的妖魔是什么劝赔? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任誓焦,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘杂伟。我一直安慰自己移层,他們只是感情好,可當我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布赫粥。 她就那樣靜靜地躺著观话,像睡著了一般。 火紅的嫁衣襯著肌膚如雪越平。 梳的紋絲不亂的頭發(fā)上频蛔,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天,我揣著相機與錄音秦叛,去河邊找鬼束倍。 笑死慰枕,一個胖子當著我的面吹牛恒序,可吹牛的內(nèi)容都是我干的悬嗓。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼避咆,長吁一口氣:“原來是場噩夢啊……” “哼舟肉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起查库,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤路媚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后膨报,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體磷籍,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡适荣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年现柠,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弛矛。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡够吩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出丈氓,到底是詐尸還是另有隱情周循,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布万俗,位于F島的核電站湾笛,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏闰歪。R本人自食惡果不足惜嚎研,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望库倘。 院中可真熱鬧临扮,春花似錦论矾、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蚜退,卻和暖如春闰靴,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背钻注。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工传黄, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人队寇。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓膘掰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親佳遣。 傳聞我的和親對象是個殘疾皇子识埋,可洞房花燭夜當晚...
    茶點故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內(nèi)容