Swift學習筆記十七之協(xié)議

1、協(xié)議:定義一個規(guī)則去實現(xiàn)特定的功能,類荠卷、結構體、枚舉都可以遵守這樣的協(xié)議烛愧,并為這個協(xié)議的規(guī)則提供具體實現(xiàn)

protocol SomeProtocol1 {//協(xié)議語法
//協(xié)議內(nèi)容
}

struct SomeStructure: SomeProtocol1 {//遵守協(xié)議油宜,冒號(:)后面加協(xié)議名稱,多個協(xié)議之間用逗號隔開
//結構體內(nèi)容
}

class SomeClass: NSObject,SomeProtocol1 {//有父類的類遵守協(xié)議怜姿,要將父類名放在協(xié)議名之前慎冤,用逗號隔開
//類的實現(xiàn)
}

2、在協(xié)議中定義屬性:協(xié)議中的屬性可以是實例屬性也可以是類型屬性沧卢,協(xié)議中的屬性只能指定名稱和類型以及可讀可寫

protocol SomeProtocol2 {
var mustBeSettable: Int{ get set}//類型后面加{ get set }表示該屬性可讀可寫
var onlyRead: Int{ get } //類型后面加{ get }表示該屬性可讀
static var someTypeProperty: Int { get set }//類型屬性前面加關鍵字static

}

protocol FullyNamed { // 這個協(xié)議中只包含一個實例屬性
var fullName: String { get }
}

struct Person: FullyNamed { // Person遵守FullyNamed協(xié)議表示必需要實現(xiàn)fullName屬性
var name: String
var fullName: String { // 這個fullName屬性可以實現(xiàn)為只讀的
return "Barack Hussein (name)"
}
}
let obama = Person(name: "Obama")
print(obama.fullName) // Barack Hussein Obama
3蚁堤、在協(xié)議中定義方法:協(xié)議可以要求實現(xiàn)指定的實例方法和類方法,定義的方式和普通方法相同搏恤,但不需要大括號和方法體

protocol SomeProtocol3 {
static func someTypeMethod() // 定義類方法的時候用static作前綴
}

protocol RandomNum { // 要求遵守協(xié)議的類型必須有一個名為random的方法
func random() -> Int
}
class RandomNumGenerator: RandomNum{
func random() -> Int {
return Int(arc4random() % 10)
}
}
let randomNum = RandomNumGenerator()
print(randomNum.random()) // 0~9的隨機數(shù)

4违寿、Mutating關鍵字在協(xié)議中的應用:在結構體和枚舉即值類型的實例方法中湃交,不能直接修改其實例屬性,需要在其方法前面加Mutating關鍵字

protocol toggleProtocol {
mutating func toggle() // 對于需要結構體和枚舉遵守的協(xié)議方法需要在前面添加mutating
}

enum Toggle: toggleProtocol {
case Off, On
mutating func toggle() {
switch self {
case .Off:
self = .On
case .On:
self = .Off
}
}
}

var lightSwitch = Toggle.Off
lightSwitch.toggle() // 置反
print(lightSwitch == .On) // true

5藤巢、在協(xié)議中定義構造器:寫下構造器的聲明搞莺,但不需要寫花括號和結構器實體
protocol SomeProtocol4 {
init(someParameter: Int)
}

class SomeInitClass: SomeProtocol4 {
// 遵守協(xié)議的構造器都必須在前面帶required修飾符,來確保所有子類都要實現(xiàn)此構造器
required init(someParameter: Int) {
// 構造器實現(xiàn)部分
}
}

6、協(xié)議作為類型使用:可以作為函數(shù)方法和構造器中的參數(shù)類型或返回值類型掂咒,作為常量變量或?qū)傩缘念愋筒挪祝鳛閿?shù)組字典或其他容器中元素的類型
class Dice { // 定義一個骰子
let generator: RandomNum // 協(xié)議類型的存儲屬性
init(generator: RandomNum) {
self.generator = generator
}
func roll() -> Int { // 產(chǎn)生一個隨機數(shù)
return generator.random()
}
}

class RandomNumGenerator1: RandomNum{ // 定義一個類遵守該協(xié)議
func random() -> Int {
return Int(arc4random() % 10)
}
}

var d6 = Dice(generator: RandomNumGenerator1()) // 就可以將遵守該協(xié)議的類當作參數(shù)了
print(d6.roll()) // 隨機數(shù)

7、代理設計模式:可以將類或結構體的一些功能委托給其他類型去實現(xiàn)绍刮,代理可以用來響應事件或接收外部數(shù)據(jù)源數(shù)據(jù)
class Baby {
var needNumFood: Int? // baby需要的食物數(shù)量
var babyDelegate: BabyDelegate? // 代理屬性
func eat() { // 吃這個方法
babyDelegate?.feedBaby(baby: self) // 調(diào)用代理方法
}
}

class Nanny: BabyDelegate{ // nanny遵守代理
func feedBaby(baby: Baby) { // nanny實現(xiàn)喂食物的代理方法
baby.needNumFood = 10
print("喂baby食物:(baby.needNumFood!)") // 喂baby食物:10
}
}

let baby = Baby()
let nanny = Nanny()

baby.babyDelegate = nanny // 將baby委托給nanny
baby.eat() // baby調(diào)用吃的方法委托nanny喂食物

8温圆、在extention中實現(xiàn)協(xié)議

protocol SomeProtocol5 {
// 協(xié)議內(nèi)容
}
extension Nanny: SomeProtocol5 { // 在擴展中遵守協(xié)議的效果和在原始類中一樣
// 在實際開發(fā)中實現(xiàn)協(xié)議的時候推薦這樣做,有利于提高代碼的閱讀性
}
9、通過擴展遵守協(xié)議:當一個類實現(xiàn)了協(xié)議中的方法孩革,卻還沒有遵守該協(xié)議時岁歉,可以通過空擴展體來遵守該協(xié)議

protocol SomeProtocol6 {
var description: String { get }
}
struct Cat { // 并沒有遵守協(xié)議
var name: String
var description: String { // 實現(xiàn)協(xié)議中的方法
return "A cat named: (name)"
}
}
extension Cat: SomeProtocol6 {} // 在擴展中實現(xiàn)協(xié)議

let lucyTheCat = Cat(name: "lucy")
let sp: SomeProtocol6 = lucyTheCat // 遵守協(xié)議
print(sp.description) // A cat named: lucy

10、協(xié)議本身也是類型膝蜈,可以放到集合中使用
let things: [SomeProtocol6] = [lucyTheCat] // 用于存放遵守協(xié)議的類
for thing in things {
print(thing.description) // A cat named: lucy
}

11锅移、協(xié)議的繼承:和類的繼承相似,但協(xié)議可以繼承一個或多個其它協(xié)議

protocol InheritingProtocol: SomeProtocol5, SomeProtocol6 {
// 任何實現(xiàn)InheritingProtocol協(xié)議的同時,也必須實現(xiàn)SomeProtocol5和SomeProtocol6
}

12饱搏、 類的專屬協(xié)議:通過添加class關鍵字來限制協(xié)議只能被類遵守
protocol SomeClassOnlyProtocol: class, InheritingProtocol { // class關鍵字必須出現(xiàn)在最前面
// 如果被結構體或枚舉繼承則會導致編譯錯誤
}

13非剃、協(xié)議合成:同時采納多個協(xié)議,多個協(xié)議之間用&分割推沸,協(xié)議的合成并不會生成新的協(xié)議類型备绽,只是一個臨時局部的
protocol Name {
var name: String { get }
}
protocol Age {
var age: Int { get }
}

struct People: Name, Age { // 遵守name age這兩個協(xié)議
var name: String
var age: Int
}

func say(to people: Name & Age) { // 參數(shù)類型:Name & Age
print("This is (people.name), age is (people.age)") // This is Joan, age is 20
}

let p = People(name: "Joan", age: 20)
say(to: p)

14、檢查協(xié)議的一致性鬓催,如果不一致可以進行轉(zhuǎn)換

// is 檢查實例是否符合某個協(xié)議,符合返回true,否則返回false
// as? 如果符合某個協(xié)議類型,返回類型為協(xié)議類型的可選值, 否則返回nil
// as! 將實例強制轉(zhuǎn)化為某個協(xié)議類型,如果失敗會引發(fā)運行時錯誤
protocol HasArea { // HasArea協(xié)議
var area: Double { get }
}
class Circle: HasArea { // 遵守HasArea協(xié)議
let pi = 3.1415927
var radius: Double
var area: Double { return pi * radius * radius}
init(radius: Double) { self.radius = radius }
}

class Country: HasArea { // 遵守HasArea協(xié)議
var area: Double
init(area: Double) { self.area = area }
}

class Animal {
var legs: Int
init(legs: Int) { self.legs = legs }
}

15肺素、將所有類對象作為AnyObject對象放到數(shù)組中

let objects: [AnyObject] = [ Circle(radius: 3.0), Country(area: 23460), Animal(legs: 4)]
for object in objects {
if let objectWithArea = object as? HasArea { // 判斷object是否遵守area協(xié)議
print(objectWithArea.area) // 此時的objectWithArea是area協(xié)議類型的實例
print(objectWithArea.pi) // ?, 所以只有area屬性才能被訪問
}else {
print("沒有遵守area協(xié)議")
}
}

16、協(xié)議的可選要求:協(xié)議中所有的方法深浮,屬性并不都是一定要實現(xiàn)的压怠,可以在實現(xiàn)和不實現(xiàn)的方法 面前加optional關鍵字,使用可選方法或?qū)傩詴r飞苇,他們的類型會自動變?yōu)榭蛇x的

// 注意: 可選的協(xié)議前面需要加@objc關鍵字.
// @objc:表示該協(xié)議暴露給OC代碼,但即使不與OC交互只想實現(xiàn)可選協(xié)議要求,還是要加@objc關鍵字.
// 帶有@objc關鍵字的協(xié)議只能被OC類,或者帶有@objc關鍵字的類遵守,結構體和枚舉都不能遵守.
@objc protocol CounterDataSource { // 用于計數(shù)的數(shù)據(jù)源
@objc optional var fixAdd: Int { get } // 可選屬性
@objc optional func addForCount(count: Int) -> Int // 可選方法,用于增加數(shù)值
}
class Counter: CounterDataSource {
var count = 0 // 用來存儲當前值
var dataSource: CounterDataSource?
func add() { // 增加count值
// 使用可選綁定和兩層可選鏈式調(diào)用來調(diào)用可選方法
if let amount = dataSource?.addForCount?(count: count) {
count += amount
}else if let amount = dataSource?.fixAdd {
count += amount
}
}
}
class ThreeSource: NSObject, CounterDataSource {
let fixAdd = 3
}

var counter = Counter()
counter.dataSource = ThreeSource() // 將counter的數(shù)據(jù)源設置為ThreeSource
counter.add() // 增加3
counter.add() // 增加3
print(counter.count) // 6

17菌瘫、協(xié)議的擴展:可以通過擴展協(xié)議來遵守協(xié)議的類型提供屬性方法下標

protocol RandomNumG {
func random() -> Int
}
class RandomNumGen: RandomNumG {
var description: String {
return "RandomNumGen"
}
func random() -> Int {
return Int(arc4random() % 10) // 返回一個0~9的隨機數(shù)
}
}

let randomNumG = RandomNumGen()
print(randomNumG.random()) // 0~9的隨機數(shù)

extension RandomNumG {
var description: String {
return "extension"
}
func randomBool() -> Bool { // 可以通過擴展來為協(xié)議添加方法
return random() > 4 // 隨機數(shù)是否大于4
}
}
print(randomNumG.randomBool()) // bool值
print(randomNumG.description) // RandomNumGen,協(xié)議擴展中的默認屬性的優(yōu)先級比自定義屬性低

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市布卡,隨后出現(xiàn)的幾起案子雨让,更是在濱河造成了極大的恐慌,老刑警劉巖忿等,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件栖忠,死亡現(xiàn)場離奇詭異,居然都是意外死亡姓赤,警方通過查閱死者的電腦和手機痛黎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來月匣,“玉大人捐川,你說我怎么就攤上這事脓鹃。” “怎么了古沥?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵瘸右,是天一觀的道長。 經(jīng)常有香客問我岩齿,道長太颤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任盹沈,我火速辦了婚禮龄章,結果婚禮上,老公的妹妹穿的比我還像新娘襟诸。我一直安慰自己瓦堵,他們只是感情好,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布歌亲。 她就那樣靜靜地躺著,像睡著了一般澜驮。 火紅的嫁衣襯著肌膚如雪陷揪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天杂穷,我揣著相機與錄音悍缠,去河邊找鬼。 笑死耐量,一個胖子當著我的面吹牛飞蚓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播廊蜒,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼趴拧,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了山叮?” 一聲冷哼從身側(cè)響起著榴,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎屁倔,沒想到半個月后脑又,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年问麸,在試婚紗的時候發(fā)現(xiàn)自己被綠了往衷。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡严卖,死狀恐怖炼绘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情妄田,我是刑警寧澤俺亮,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站疟呐,受9級特大地震影響脚曾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜启具,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一本讥、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鲁冯,春花似錦拷沸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至跨扮,卻和暖如春序无,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背衡创。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工帝嗡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人璃氢。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓哟玷,卻偏偏與公主長得像,于是被迫代替她去往敵國和親一也。 傳聞我的和親對象是個殘疾皇子巢寡,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355

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