[Swift5.1] 14-協(xié)議

協(xié)議(Protocol)

1)協(xié)議可以用來(lái)定義方法河泳、屬性构诚、下標(biāo)的聲明徘层,協(xié)議可以被枚舉组砚、結(jié)構(gòu)體吻商、類(lèi)遵守(多個(gè)協(xié)議之間用逗號(hào)隔開(kāi))

protocol Drawable {
    func draw()
    var x: Int { get set }
    var y: Int { get }
    subscript(index: Int) -> Int { get set }
}
protocol Test1 {}
protocol Test2 {}
protocol Test3 {}
class TestClass : Test1, Test2, Test3 {}

2)協(xié)議中定義方法時(shí)不能有默認(rèn)參數(shù)值
默認(rèn)情況下,協(xié)議中定義的內(nèi)容必須全部都實(shí)現(xiàn)
也有辦法辦到只實(shí)現(xiàn)部分內(nèi)容糟红,以后會(huì)講到

協(xié)議中的屬性

protocol Drawable {
    func draw()
    var x : Int { get set }
    var y : Int { get }
    subscript(index: Int) -> Int { get set }
}

class Person : Drawable {
    var x: Int = 0
    let y: Int = 0
    func draw() {
        print("Person draw")
    }
    subscript(index: Int) -> Int {
        set {}
        get { index }
    }
}

class Person : Drawable {
    var x: Int {
        get { 0 }
        set {}
    }
    var y: Int { 0 }
    func draw() { print("Person draw") }
    subscript(index: Int) -> Int {
        set {}
        get { index }
    }
}
  • 協(xié)議中定義屬性時(shí)必須用var關(guān)鍵字.
  • 實(shí)現(xiàn)協(xié)議時(shí)的屬性權(quán)限要不小于協(xié)議中定義的屬性權(quán)限.
    協(xié)議定義get艾帐、set乌叶,用var存儲(chǔ)屬性或getset計(jì)算屬性去實(shí)現(xiàn)
    協(xié)議定義get柒爸,用任何屬性都可以實(shí)現(xiàn)

static准浴、class

為了保證通用,協(xié)議中必須用static定義類(lèi)型方法捎稚、類(lèi)型屬性乐横、類(lèi)型下標(biāo)

protocol Drawable {
    static func draw()
}

class Person1 : Drawable {
    class func draw() {
        print("Person1 draw")
    }
}

class Person2 : Drawable {
    static func draw() {
        print("Person2 draw")
    }
}

mutating

只有將協(xié)議中的實(shí)例方法標(biāo)記為mutating

  • 才允許結(jié)構(gòu)體、枚舉的具體實(shí)現(xiàn)修改自身內(nèi)存
  • 類(lèi)在實(shí)現(xiàn)方法時(shí)不用加mutating今野,枚舉晰奖、結(jié)構(gòu)體才需要加mutating
protocol Drawable {
    mutating func draw()
}

class Size : Drawable {
    var width: Int = 0
    func draw() {
        width = 10
    }
}

struct Point : Drawable {
    var x: Int = 0
    mutating func draw() {
        x = 10
    }
}

init

  • 協(xié)議中還可以定義初始化器init
  • 非final類(lèi)實(shí)現(xiàn)時(shí)必須加上required
protocol Drawable {
    init(x: Int, y: Int)
}

class Point : Drawable {
    required init(x: Int, y: Int) {}
}

final class Size : Drawable {
    init(x: Int, y: Int) {}
}
  • 如果從協(xié)議實(shí)現(xiàn)的初始化器,剛好是重寫(xiě)了父類(lèi)的指定初始化器
  • 那么這個(gè)初始化必須同時(shí)加required腥泥、override
protocol Livable {
    init(age: Int)
}

class Person {
    init(age: Int) {}
}

class Student : Person, Livable {
    required override init(age: Int) {
        super.init(age: age)
    }
}

init匾南、init?、init!

  • 協(xié)議中定義的init?蛔外、init!蛆楞,可以用init、init?夹厌、init!去實(shí)現(xiàn)
  • 協(xié)議中定義的init豹爹,可以用init、init!去實(shí)現(xiàn)
protocol Livable {
    init()
    init?(age: Int)
    init!(no: Int)
}

class Person : Livable {
    required init() {}
    // required init!() {}
    
    required init?(age: Int) {}
    // required init!(age: Int) {}
    // required init(age: Int) {}
    
    required init!(no: Int) {}
    // required init?(no: Int) {}
    // required init(no: Int) {}
}

協(xié)議的繼承

一個(gè)協(xié)議可以繼承其他協(xié)議

protocol Runnable {
    func run()
}

protocol Livable : Runnable {
    func breath()
}

class Person : Livable {
    func breath() {}
    func run() {}
}

協(xié)議組合

協(xié)議組合矛纹,可以包含1個(gè)類(lèi)類(lèi)型(最多1個(gè))

protocol Livable {}
protocol Runnable {}
class Person {}

// 接收Person或者其子類(lèi)的實(shí)例
func fn0(obj: Person) {}
// 接收遵守Livable協(xié)議的實(shí)例
func fn1(obj: Livable) {}
// 接收同時(shí)遵守Livable臂聋、Runnable協(xié)議的實(shí)例
func fn2(obj: Livable & Runnable) {}
// 接收同時(shí)遵守Livable、Runnable協(xié)議或南、并且是Person或者其子類(lèi)的實(shí)例
func fn3(obj: Person & Livable & Runnable) {}

typealias RealPerson = Person & Livable & Runnable
// 接收同時(shí)遵守Livable孩等、Runnable協(xié)議、并且是Person或者其子類(lèi)的實(shí)例
func fn4(obj: RealPerson) {}

CaseIterable協(xié)議

枚舉遵守CaseIterable協(xié)議采够,可以實(shí)現(xiàn)遍歷枚舉值

enum Season : CaseIterable {
    case spring, summer, autumn, winter
}
let seasons = Season.allCases
print(seasons.count) // 4
for season in seasons {
    print(season)
} // spring summer autumn winter

CustomStringConvertible協(xié)議

遵守CustomStringConvertible肄方、 CustomDebugStringConvertible協(xié)議,都可以自定義實(shí)例的打印字符串

class Person : CustomStringConvertible, CustomDebugStringConvertible {  
    var age = 0
    var description: String { "person_\(age)" }
    var debugDescription: String { "debug_person_\(age)" }
}
var person = Person()
print(person) // person_0
debugPrint(person) // debug_person_0
  • print調(diào)用的是CustomStringConvertible協(xié)議的description
  • debugPrint 蹬癌、po調(diào)用的是CustomDebugStringConvertible協(xié)議的debugDescription

Any权她、AnyObject

Swift提供了2種特殊的類(lèi)型:AnyAnyObject

  • Any:可以代表任意類(lèi)型(枚舉逝薪、結(jié)構(gòu)體隅要、類(lèi),也包括函數(shù)類(lèi)型)
  • AnyObject:可以代表任意類(lèi)類(lèi)型(在協(xié)議后面寫(xiě)上: AnyObject代表只有類(lèi)能遵守這個(gè)協(xié)議)
  • 在協(xié)議后面寫(xiě)上: class也代表只有類(lèi)能遵守這個(gè)協(xié)議
var stu: Any = 10
stu = "Jack"
stu = Student()

// 創(chuàng)建1個(gè)能存放任意類(lèi)型的數(shù)組
// var data = Array<Any>()  也等價(jià)于下面寫(xiě)法
var data = [Any]()

data.append(1)
data.append(3.14)
data.append(Student())
data.append("Jack")
data.append({ 10 })

is董济、as?步清、as!、as

is用來(lái)判斷是否為某種類(lèi)型感局,as用來(lái)做強(qiáng)制類(lèi)型轉(zhuǎn)換

protocol Runnable { func run() }
class Person {}
class Student : Person, Runnable {
    func run() {
        print("Student run")
    }
    func study() {
        print("Student study")
    }
}
var stu: Any = 10
print(stu is Int) // true
stu = "Jack"
print(stu is String) // true
stu = Student()
print(stu is Person) // true
print(stu is Student) // true
print(stu is Runnable) // true
var stu: Any = 10
(stu as? Student)?.study() // 沒(méi)有調(diào)用study
stu = Student()
(stu as? Student)?.study() // Student study
(stu as! Student).study() // Student study
(stu as? Runnable)?.run() // Student run
var data = [Any]()
data.append(Int("123") as Any)
var d = 10 as Double
print(d) // 10.0

X.self尼啡、X.Type暂衡、AnyClass

X代指類(lèi)

  • X.self是一個(gè)元類(lèi)型(metadata)的指針询微,metadata存放著類(lèi)型相關(guān)信息
  • X.self屬于X.Type類(lèi)型
class Person {}
class Student : Person {}
var perType: Person.Type = Person.self
var stuType: Student.Type = Student.self
perType = Student.self
var anyType: AnyObject.Type = Person.self
anyType = Student.self

public typealias AnyClass = AnyObject.Type
var anyType2: AnyClass = Person.self
anyType2 = Student.self
var per = Person()
var perType = type(of: per) // Person.self
print(Person.self == type(of: per)) // true

以下四種初始化效果一樣:

class Person {
    static var age : Int = 0
    static func run() {}
}

Person.age = 11
Person.run()

Person.self.age = 22
Person.self.run()

// 四種初始化效果一樣:
var p0 = Person() // init()
var p1 = Person.self() // init()
var p2 = Person.init() // init()
var p3 = Person.self.init() // init()

var pType = Person.self
//var pType2 = Person   //?編譯錯(cuò)誤
  • 如果想訪問(wèn)類(lèi)屬性,或者類(lèi)方法, 可以通過(guò)類(lèi)名(Person), 或者Person.self訪問(wèn).
  • 如果想要獲取元類(lèi)型,只能通過(guò)類(lèi)名.self(Person.self)方式獲取
  • AnyClass 實(shí)質(zhì)就是 AnyObject.Type, 如果要求傳入AnyClass, 就是傳入任何類(lèi)的元類(lèi)類(lèi)型(Person.self)
func test(_ cls:AnyClass) {
}
test(Person.self)

元類(lèi)型的應(yīng)用

class Animal { required init() {} }
class Cat : Animal {}
class Dog : Animal {}
class Pig : Animal {}

func create(_ clses: [Animal.Type]) -> [Animal] {
    var arr = [Animal]()
    for cls in clses {
        arr.append(cls.init())
    }
    return arr
}

print(create([Cat.self, Dog.self, Pig.self]))
import Foundation  class Person {
    var age: Int = 0
}
class Student : Person {
    var no: Int = 0
}
print(class_getInstanceSize(Student.self)) // 32
print(class_getSuperclass(Student.self)!) // Person
print(class_getSuperclass(Person.self)!) // Swift._SwiftObject

從結(jié)果可以看得出來(lái)崖瞭,Swift還有個(gè)隱藏的基類(lèi):Swift._SwiftObject
可以參考Swift源碼 34行

Self

  • Self代表當(dāng)前類(lèi)型, self代表當(dāng)前實(shí)例對(duì)象
class Person {
    var age = 1
    static var count = 2
    func run() {
        print(self.age) // 1
        print(Self.count) // 2
    }
}

Self一般用作返回值類(lèi)型,限定返回值跟方法調(diào)用者必須是同一類(lèi)型(也可以作為參數(shù)類(lèi)型)

protocol Runnable {
    func test() -> Self
}
class Person : Runnable {
    required init() {}
    func test() -> Self { type(of: self).init() }
}
class Student : Person {}

var p = Person()
// Person  print(p.test())

var stu = Student()
// Student  print(stu.test())
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
禁止轉(zhuǎn)載撑毛,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者书聚。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市藻雌,隨后出現(xiàn)的幾起案子雌续,更是在濱河造成了極大的恐慌,老刑警劉巖胯杭,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件驯杜,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡做个,警方通過(guò)查閱死者的電腦和手機(jī)鸽心,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)居暖,“玉大人顽频,你說(shuō)我怎么就攤上這事√耄” “怎么了糯景?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)省骂。 經(jīng)常有香客問(wèn)我蟀淮,道長(zhǎng),這世上最難降的妖魔是什么钞澳? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任灭贷,我火速辦了婚禮,結(jié)果婚禮上略贮,老公的妹妹穿的比我還像新娘甚疟。我一直安慰自己,他們只是感情好逃延,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布览妖。 她就那樣靜靜地躺著,像睡著了一般揽祥。 火紅的嫁衣襯著肌膚如雪讽膏。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,624評(píng)論 1 305
  • 那天拄丰,我揣著相機(jī)與錄音府树,去河邊找鬼俐末。 笑死,一個(gè)胖子當(dāng)著我的面吹牛奄侠,可吹牛的內(nèi)容都是我干的卓箫。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼垄潮,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼烹卒!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起弯洗,我...
    開(kāi)封第一講書(shū)人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤旅急,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后牡整,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體藐吮,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年逃贝,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了谣辞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡秋泳,死狀恐怖潦闲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情迫皱,我是刑警寧澤歉闰,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站卓起,受9級(jí)特大地震影響和敬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜戏阅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一昼弟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧奕筐,春花似錦舱痘、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至渊胸,卻和暖如春旬盯,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工胖翰, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留接剩,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓萨咳,卻偏偏與公主長(zhǎng)得像懊缺,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子某弦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355