swift 的protocol學(xué)習(xí)筆記

? ? ? ?代理又稱為協(xié)議捏顺,委托六孵,protocol ,是iOS開發(fā)中經(jīng)常用到的設(shè)計(jì)模式幅骄。剛學(xué)習(xí)iOS的時(shí)候不是特別理解代理的用法劫窒,估計(jì)是隨著工作中經(jīng)常用,消息傳遞昌执,頁面?zhèn)髦档戎蛞啵?jīng)常用到代理模式诈泼,慢慢對(duì)代理有了點(diǎn)自己的理解懂拾。

OC中的代理模式使用簡(jiǎn)單總結(jié):

1. 定義一個(gè)協(xié)議? 定義遵守協(xié)議的類要實(shí)現(xiàn)的方法

@protocolprotocol name

methods

@end

2. 聲明一個(gè)代理屬性

@property(nonatomic,weak)id delegate;?

3.在另一個(gè)類中遵循協(xié)議

4.給有代理屬性的類設(shè)置代理,即遵循代理的铐达,一般是self

5.遵循代理的類實(shí)現(xiàn)代理方法

我是最近才開始學(xué)swift的岖赋,學(xué)swift 的protocol是對(duì)照這OC學(xué)習(xí)的。swift 中的代理和OC中代理用法差不多瓮孙,用法更加廣泛唐断,更加簡(jiǎn)潔一些。今天看一個(gè)swift開源項(xiàng)目高仿最美應(yīng)用高仿最美應(yīng)用杭抠,類似QQ的側(cè)滑菜單的功能脸甘,中間大量使用了代理來傳遞消息。比如點(diǎn)擊首頁頂部的btn事件偏灿,需要btn去響應(yīng)首頁測(cè)滑的事件丹诀,為了解藕,btn把事件傳給頂部視圖的代理翁垂,頂部視圖的代理傳給首頁VC铆遭,首頁VC代理傳給RootVC去做了。

項(xiàng)目中側(cè)滑菜單實(shí)現(xiàn)原理:主要使用了UINavigationController.interactivePopGestureRecognizer這個(gè)pop手勢(shì)沿猜。在rootVC中添加兩個(gè)VC枚荣,leftVC,RightVC啼肩,定義一個(gè)紀(jì)錄當(dāng)前VC的currentVC橄妆,并且將兩個(gè)vc的View添加到self.view,在currentVC上再添加一個(gè)覆蓋window衙伶,在window上添加手勢(shì)動(dòng)作。

結(jié)合項(xiàng)目學(xué)習(xí)會(huì)不那么枯燥害碾。

下面是我的swift protocol學(xué)習(xí)筆記

protocol SomeProtocol {

//這里是協(xié)議的定義部分

}

? ? ? ?讓自定義類型遵循某個(gè)協(xié)議痕支,在類型名稱后加上協(xié)議名稱,中間以冒號(hào)(:)分隔蛮原。遵循多個(gè)協(xié)議時(shí)卧须,各協(xié)議之間用逗號(hào)(,)分隔

struct SomeStructre:FirstProtocol, AnotherProtocol {

//這里時(shí)結(jié)構(gòu)體的定義部分

}

擁有父類的類在遵循協(xié)議時(shí)儒陨,應(yīng)該將父類名放在協(xié)議名之前花嘶,以逗號(hào)分隔

class someClass:SomeSuperClass, FirstProtocol,AnotherProtocol {

// 這里是類的定義部分

}

屬性要求

協(xié)議可以要求遵循協(xié)議的類型提供特定名稱和類型的實(shí)例屬性。協(xié)議不指定屬性是存儲(chǔ)型屬性還是計(jì)算屬性蹦漠,它只是制定屬性的名稱和類型椭员。

protocol SomeProtocol {

var mustBeSettable:Int {get set}

var doesNotNeedToBeSettable:Int {get}

}

在協(xié)議中定義屬性時(shí),總是使用static關(guān)鍵字作為前綴笛园。當(dāng)類型遵循協(xié)議時(shí)隘击,除了static關(guān)鍵字,還可以使用class關(guān)鍵字來聲明類型屬性

protocol AnotherProtocol {

static var someTypeProoerty:Int {get set}

}

protocol FullyNamed {

var fullName:String {get}

}

// FullyNamed協(xié)議除了要求遵循協(xié)議的類型提供fullName屬性外研铆,并沒有其他特別的要求埋同。這個(gè)協(xié)議表示,在任何遵循FullyNamed的類型棵红,都必須有一個(gè)可讀的String類型的實(shí)例屬性fullName凶赁。

struct Person:FullyNamed {

var? fullName: String

}

let john = Person(fullName: "john Appleseed")

// Person 結(jié)構(gòu)體的每一個(gè)實(shí)例都有一個(gè)String類型的存儲(chǔ)類型屬性fullName。這正好滿足了FullyNamed協(xié)議的要求逆甜,也就意味著Person結(jié)構(gòu)體正確地附和了協(xié)議虱肄。

class Startship:FullyNamed {

var prefix:String?

var name:String

init(name:String, prefix:String?=nil) {

self.name = name

self.prefix = prefix

}

var fullName: String {

return (prefix != nil ? prefix! + " ":"") + name

}

}

// 方法要求

// 協(xié)議可以要求遵循協(xié)議的類型實(shí)現(xiàn)某些指定的實(shí)例方法或者類方法

protocol RangedomNumberGenerator {

func random() -> Double

}

class LinearCongtuentialGenerator:RangedomNumberGenerator {

var lastRandom = 42.0

let m = 139968.0

let a = 3877.0

let c = 29573.0

// 實(shí)現(xiàn)RangedomNumberGenerator協(xié)議random方法

func random() -> Double {

lastRandom = (lastRandom * a + c).truncatingRemainder(dividingBy: m)

return lastRandom / m

}

}

let generator = LinearCongtuentialGenerator()

generator.random()

(generator.random())

protocol Togglable {

mutating func toggle()

}

enum OnOffSwitch:Togglable {

case Off, On

mutating func toggle() {

switch self {

case .Off:

self = .On

case .On:

self = .Off

}

}

}

var lightSwitch = OnOffSwitch.Off

lightSwitch.toggle()

// 作為類型

class Dice {

let sides:Int

let generator:RangedomNumberGenerator

init(sides:Int, generator:RangedomNumberGenerator) {

self.sides = sides

self.generator = generator

}

func roll() -> Int {

return Int(generator.random() * Double(sides))

}

}

// Dice初始化兩個(gè)參數(shù) sides generator是一個(gè)遵循了RangedomNumberGenerator協(xié)議的類的實(shí)例

var d6 = Dice(sides: 6, generator: LinearCongtuentialGenerator())

for _ in 1...5 {

print("random dice roll is \(d6.roll())")

}

// 委托代理模式

// 委托是一種設(shè)計(jì)模式,它允許類或者結(jié)構(gòu)體將一些需要它們負(fù)責(zé)的功能委托給其他類型的實(shí)例交煞。委托模式實(shí)現(xiàn)很簡(jiǎn)單:定義協(xié)議來封裝那些需要被委托的功能咏窿,這樣就能確保遵循協(xié)議的類型能提供這些功能。委托模式可以用來響應(yīng)特定的動(dòng)作素征,或者接收外部數(shù)據(jù)源提供的數(shù)據(jù)集嵌,而無需關(guān)心外部數(shù)據(jù)源的類型

protocol Dicegame {

var dice:Dice {get}

// 定義Dicegame協(xié)議方法play()

func play()

}

protocol DicegameDelegate {

// Dicegame 作為類型

func gameDidStart(_ game:Dicegame)

func game(_ game:Dicegame, didStartNewTurnWithDiceRoll diceRoll:Int)

func gameDidEnd(_ game:Dicegame)

}

// 遵循Dicegame協(xié)議

class SnakesAndLadders:Dicegame {

let finalSquare = 25

let dice = Dice(sides: 6, generator: LinearCongtuentialGenerator())

var square = 0

var board:[Int]

init () {

board = [Int](repeating:0, count:finalSquare + 1)

board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02

board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08

}

// 定義代理

var delegate:DicegameDelegate?

// 實(shí)現(xiàn) Dicegame協(xié)議 的play()方法

func play() {

square = 0

// 調(diào)用DicegameDelegate的代理方法? 參數(shù)是Dicegame類型的實(shí)例

delegate?.gameDidStart(self)

gameLoop:while square != finalSquare {

let diceRoll = dice.roll()

delegate?.game(self, didStartNewTurnWithDiceRoll:diceRoll)

switch square + diceRoll {

case finalSquare:

break gameLoop

case let newSquare where newSquare > finalSquare:

continue gameLoop

default:

square += diceRoll

square += board[square]

}

}

delegate?.gameDidEnd(self)

}

}

// 這個(gè)版本的游戲封裝到了 SnakesAndLadders 類中,該類遵循了 Dicegame 協(xié)議稚茅,并且提供了相應(yīng)的可讀的dice屬性和play()方法

// 游戲使用SnakesAndLadders類init()構(gòu)造器來初始化游戲.所有的游戲邏輯被轉(zhuǎn)移到了協(xié)議中的play()方法纸淮,play()方法使用協(xié)議要求的dice屬性提供骰子搖出的值。

// 注意亚享,delegate并不是游戲的必備條件咽块,因此delegate被定義DicegameDelegate類型的可選屬性。因?yàn)閐elegate是可選值欺税,因此會(huì)被自動(dòng)賦予初始值nill侈沪。隨后揭璃,可以在游戲中為delegate設(shè)置適當(dāng)?shù)闹怠?/p>

// DicegameDelegate協(xié)議提供了三個(gè)方法用來追蹤游戲的過程。這三個(gè)方法被放置在play方法內(nèi)亭罪,分別在游戲開始時(shí)瘦馍,新一輪開始時(shí),以及游戲結(jié)束時(shí)被調(diào)用

// 因?yàn)閐elegate是一個(gè)DicegameDelegate類型的可選屬性应役,因此在play()方法中通過可選鏈?zhǔn)秸{(diào)用來調(diào)用它的方法情组。若delegate屬性為nill,則調(diào)用方法會(huì)優(yōu)雅地失敗箩祥,并不會(huì)產(chǎn)生錯(cuò)誤院崇,若delegate不為nill,則方法能夠被調(diào)用袍祖,并傳遞SnakesAndLadders實(shí)例為參數(shù)

// DiceGameTracker類遵循DicegameDelegate協(xié)議

class DiceGameTracker:DicegameDelegate {

var numberOfTurns = 0

// 實(shí)現(xiàn)DicegameDelegate方法

func gameDidStart(_ game: Dicegame) {

numberOfTurns = 0

if game is SnakesAndLadders {

print("Start a new game of Snakes and Ladders")

}

print("The game is using a \(game.dice.sides)-side dice")

}

func game(_ game: Dicegame, didStartNewTurnWithDiceRoll diceRoll: Int) {

numberOfTurns += 1

print("Rolled a \(diceRoll)")

}

func gameDidEnd(_ game: Dicegame) {

print("The game lasted for \(numberOfTurns) turns")

}

}

// DiceGameTracker類遵循DicegameDelegate協(xié)議 實(shí)例

let tracker = DiceGameTracker()

// 遵循Dicegame協(xié)議 的實(shí)例

let game = SnakesAndLadders()

// 設(shè)置game的代理為 tracker

game.delegate = tracker

//? 調(diào)用play方法

game.play()

protocol TextRepresentable {

var textualDescription:String {get}

}

extension Dice:TextRepresentable {

var textualDescription:String {

return "A \(sides)-sided dice"

}

}

let dl2 = Dice(sides: 12, generator: LinearCongtuentialGenerator())

print(dl2.textualDescription)

// 通過擴(kuò)展遵循協(xié)議

extension SnakesAndLadders:TextRepresentable {

var textualDescription:String {

return "A game of Snakes and Ladders with \(finalSquare) squares"

}

}

print(game.textualDescription)

struct Hamster {

var name:String

var textualDescription:String {

return "A hamster named \(name)"

}

}

extension Hamster:TextRepresentable {}

let simonTheHamster = Hamster(name: "Simon")

let somethingTextRepresentable:TextRepresentable = simonTheHamster

print(somethingTextRepresentable.textualDescription)

// 協(xié)議類型的集合

let things:[TextRepresentable] = [game, dl2, simonTheHamster]

for thing in things {

print(thing.textualDescription)

}

// 協(xié)議的繼承

// 協(xié)議能夠繼承一個(gè)或者多個(gè)其他協(xié)議底瓣,可以在繼承的協(xié)議的基礎(chǔ)上增加新的要求。協(xié)議的繼承語法和類的繼承相似蕉陋,多個(gè)被繼承的協(xié)議間用逗號(hào)分隔

protocol InhertingProtocol:SomeProtocol, AnotherProtocol {

// 協(xié)議的定義部分

}

// 定義一個(gè)新的協(xié)議PrettyTextRepresentable 捐凭,它繼承自TextRepresentable 任何遵循PrettyTextRepresentable協(xié)議的類型在滿足該協(xié)議的要求時(shí),也必須滿足TextRepresentable協(xié)議的要求

protocol PrettyTextRepresentable:TextRepresentable {

var prettyTextualDescription:String {get}

}

extension SnakesAndLadders:PrettyTextRepresentable {

var prettyTextualDescription:String {

var output = textualDescription + ":\n"

for index in 1...finalSquare {

switch board[index] {

case let ladder where ladder > 0:

output += "??"

case let snake where snake < 0:

output += "??"

default:

output += "??"

}

}

return output

}

}

print(game.prettyTextualDescription)

//類類型專屬協(xié)議

// 你可以在協(xié)議的繼承列表中凳鬓,通過添加class關(guān)鍵字來限制協(xié)議只能夠被類類型遵循茁肠,而結(jié)構(gòu)體和枚舉不能遵循該協(xié)議。class關(guān)鍵字必須第一個(gè)出現(xiàn)在協(xié)議的繼承列表中村视,在其他繼承的協(xié)議之前

protocol SomeClassOnlyProtocol:class, InhertingProtocol {

// 這里是類類型專屬協(xié)議的定義部分

}

// 協(xié)議合成

// 有時(shí)候需要同時(shí)遵循多個(gè)協(xié)議官套,你可以將多個(gè)協(xié)議采用SomeProtocol&AnotherProtocol這樣的格式進(jìn)行組合,稱為協(xié)議合成蚁孔。你可以羅列任意多個(gè)你想要遵循的協(xié)議,以符號(hào)&分隔

protocol Named {

var name:String {get}

}

protocol Aged {

var age:Int {get}

}

struct Person1: Named , Aged {

var name: String

var age: Int

}

// 遵循Named和Aged兩個(gè)協(xié)議的類型 不關(guān)心參數(shù)的具體類型惋嚎,只要參數(shù)復(fù)合這兩個(gè)協(xié)議即可

func wishHappyBirthday(to celebrator:Named & Aged) {

print("Happy birthday,\(celebrator.name), you're \(celebrator.age)!")

}

let birthdayPerson = Person1(name: "Malcolm", age: 21)

wishHappyBirthday(to: birthdayPerson);

// 檢查協(xié)議一致性

// 你可以使用類型轉(zhuǎn)換中描述的is 和as操作符來檢查協(xié)議的一致性杠氢,即是否符合某協(xié)議,并且可以轉(zhuǎn)換到指定的協(xié)議類型另伍。檢查和轉(zhuǎn)換到某個(gè)協(xié)議類型在語法上和類型的檢查和轉(zhuǎn)換完全相同

// is 用來檢查實(shí)例是否符合某個(gè)協(xié)議鼻百,若符合則返回ture,否則返回false

// as? 返回一個(gè)可選值摆尝,當(dāng)實(shí)例符合某個(gè)協(xié)議時(shí)温艇,返回類型為協(xié)議類型的可選值,否則返回nill

// as!將實(shí)例強(qiáng)制向下轉(zhuǎn)換到某個(gè)協(xié)議類型堕汞,如果強(qiáng)轉(zhuǎn)失敗勺爱,會(huì)引發(fā)運(yùn)行時(shí)錯(cuò)誤

protocol HasArea {

var area:Double {get}

}

class Circle:HasArea {

let pi = 3.1415927

var radius:Double

var area: Double {

return pi * radius * radius

}

init(radius:Double) {

self.radius = radius

}

}

class Country:HasArea {

var area: Double

init(area:Double) {

self.area = area

}

}

class Animal {

var legs:Int

init(legs:Int) {

self.legs = legs

}

}

// Circle,Country, Animal 并沒有一個(gè)共同的基類,盡管如此讯检,它們都是類琐鲁,它們的實(shí)例都可以作為AnyObject類型的值卫旱,存儲(chǔ)在同一個(gè)數(shù)組中

let objects:[AnyObject] = [

Circle(radius: 2.0),

Country(area: 243_610),

Animal(legs: 4)

]

// 檢查數(shù)組中的每一個(gè)元素,看它是否符合HasArea協(xié)議

for object in objects {

// 當(dāng)元素符合HasArea協(xié)議時(shí)围段,將as顾翼?操作符返回的可選值

if let objectWithArea = object as? HasArea {

print("Area is \(objectWithArea.area)")

} else {

print("Something that desen't have an area")

}

}

var ncc1701 = Startship(name: "Enterprise", prefix: "USS") ? // startship

參考:http://www.cocoachina.com/ios/20160317/15696.html

swift 官方教程

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市奈泪,隨后出現(xiàn)的幾起案子适贸,更是在濱河造成了極大的恐慌,老刑警劉巖涝桅,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件取逾,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡苹支,警方通過查閱死者的電腦和手機(jī)砾隅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來债蜜,“玉大人晴埂,你說我怎么就攤上這事⊙岸ǎ” “怎么了儒洛?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)狼速。 經(jīng)常有香客問我琅锻,道長(zhǎng),這世上最難降的妖魔是什么向胡? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任恼蓬,我火速辦了婚禮,結(jié)果婚禮上僵芹,老公的妹妹穿的比我還像新娘处硬。我一直安慰自己,他們只是感情好拇派,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布荷辕。 她就那樣靜靜地躺著,像睡著了一般件豌。 火紅的嫁衣襯著肌膚如雪疮方。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天茧彤,我揣著相機(jī)與錄音骡显,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蟆盐,可吹牛的內(nèi)容都是我干的承边。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼石挂,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼博助!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起痹愚,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤富岳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后拯腮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體窖式,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年动壤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了萝喘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡琼懊,死狀恐怖阁簸,靈堂內(nèi)的尸體忽然破棺而出枣耀,到底是詐尸還是另有隱情吆寨,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布托修,位于F島的核電站醉旦,受9級(jí)特大地震影響饶米,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜车胡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一檬输、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧吨拍,春花似錦褪猛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽碳却。三九已至队秩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間昼浦,已是汗流浹背馍资。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留关噪,地道東北人鸟蟹。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓乌妙,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親建钥。 傳聞我的和親對(duì)象是個(gè)殘疾皇子藤韵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

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

  • 132.轉(zhuǎn)換錯(cuò)誤成可選值 通過轉(zhuǎn)換錯(cuò)誤成一個(gè)可選值,你可以使用 try? 來處理錯(cuò)誤。當(dāng)執(zhí)行try?表達(dá)式時(shí),如果...
    無灃閱讀 1,251評(píng)論 0 3
  • 1熊经、范型范型所解決的問題 函數(shù)泽艘、方法、類型:類镐依,結(jié)構(gòu)體匹涮,枚舉,元組類型槐壳,協(xié)議參數(shù)然低,返回值,成員函數(shù)參數(shù)务唐,成員屬性類...
    我是小胡胡123閱讀 824評(píng)論 0 1
  • 協(xié)議定義了一個(gè)藍(lán)圖 規(guī)定了用來實(shí)現(xiàn)某一特定工作或者功能所必需的方法和屬性類 結(jié)構(gòu)體 枚舉類型都可以遵循協(xié)議 并提供...
    無名氏_1閱讀 602評(píng)論 0 1
  • 基礎(chǔ)部分(The Basics) 當(dāng)推斷浮點(diǎn)數(shù)的類型時(shí)雳攘,Swift 總是會(huì)選擇Double而不是Float。 結(jié)合...
    gamper閱讀 1,286評(píng)論 0 7
  • 1.安裝 Realm github下載地址 如果使用cocoapods,示例語句如下platform :ios,...
    Ego_1973閱讀 1,182評(píng)論 0 1