協(xié)議,可以理解為一個(gè)類(lèi)型,協(xié)議跟繼承有點(diǎn)像
協(xié)議,就是規(guī)定一個(gè)東西應(yīng)該有那些屬性,有哪些方法
我們可以先定義一個(gè)協(xié)議
protocol Pet{//協(xié)議里邊不能用let
var name:String {set get}//可讀可寫(xiě)的屬性
var age:Int {get}
func playWith()//協(xié)議里邊,只寫(xiě)方法定義
func init(name:String)//構(gòu)造方法
func fed(food:String)//不能默認(rèn)值
}
再來(lái)定義一個(gè)類(lèi)(或者結(jié)構(gòu)體等類(lèi)型)來(lái)遵循這個(gè)協(xié)議
class Cat:Pet{
private var myName:String?//這個(gè)私有變量,是為了寫(xiě)協(xié)議里邊的計(jì)算屬性的set,get方法
required init(name: String) {
self.name = name
}
//這里,我們用一個(gè)計(jì)算型屬性來(lái)實(shí)現(xiàn)協(xié)議里的name屬性,如果是可讀可寫(xiě)的,我么可以簡(jiǎn)單的寫(xiě)上 var name:String,就和下邊的是等價(jià)的了,如果是get-only的屬性,我們可以let age:Int,就可以了,但是,我們也可以直接用var age:Int,這樣age就是一個(gè)可讀可寫(xiě)的屬性了,這樣是允許的,協(xié)議只規(guī)定了要有一個(gè)age,并且包含get方法就行。這一點(diǎn)很重要
var name: String{
set{
myName = newValue
}
get{
return myName ?? "meiyou"
}
}
func playWith() {
}
func fed(food: String) {
}
}
這里,協(xié)議里邊的方法,默認(rèn)都是required
如果想有可選方法,可以這樣寫(xiě)
@objc protocol Pet{//協(xié)議里邊不能用let
var name:String { set get }
@objc optional func playWith()//可選方法
func fed(food:String)//不能默認(rèn)值
}
可以看到在protocol里邊,有一個(gè)構(gòu)造方法,那么,遵循這個(gè)協(xié)議的類(lèi)或者結(jié)構(gòu)體等,都需要重寫(xiě)這個(gè)構(gòu)造方法
在Cat這個(gè)類(lèi)里邊,要這樣
//這里,required表示必須實(shí)現(xiàn),如果Cat還有子類(lèi),那么子類(lèi)也必須寫(xiě)init方法
required init(name: String) {
}
如果Cat這樣寫(xiě)
final class Cat:Pet{
那么init方法就不需要required了,因?yàn)槲覀円呀?jīng)聲明了這個(gè)類(lèi)不可以被繼承
我們來(lái)提一下泛型
試想一下我們有這么一個(gè)方法,交換兩個(gè)對(duì)象,可以是整型,可以是字符串,可以是Double等等,當(dāng)然我們可以寫(xiě)三個(gè)函數(shù),函數(shù)名是一樣的,只是參數(shù)不一樣,也就是用到函數(shù)的重載,這樣就會(huì)有很多重復(fù)的邏輯,我們可以寫(xiě)一個(gè)這樣的函數(shù)
func exchange<R>(a:inout R, b: inout R){//這里,R是一個(gè)自己定義的,一般我們寫(xiě)的是T,系統(tǒng)也是用的T
(a,b) = (b,a)//這里利用元組來(lái)實(shí)現(xiàn)交換
}
其實(shí)系統(tǒng)的很多都是泛型類(lèi)型的,典型的有Array, Dictionary,Set等容器類(lèi)型的都是泛型類(lèi)型
我們?cè)賮?lái)說(shuō)一下協(xié)議里邊別名的用法(associatedtype, typealias)
protocol Weight{
associatedtype weightType//關(guān)聯(lián)一個(gè)類(lèi)型,這里,就相當(dāng)于是定義了一個(gè)類(lèi)型,可以理解為是一個(gè)泛型
var weight:weightType{ get }
}
用的時(shí)候,可以自定義weightType的類(lèi)型,比如這樣
class iPhone6s:Weight{
typealias weightType = Double//給協(xié)議里的泛型指定一個(gè)具體類(lèi)型
var weight: weightType{
return 123.123
}
}
let iphone = iPhone6s()
iphone.weight