一、繼承(Inheritance)
-
1.1井氢、類繼承
- 值類型(枚舉弦追、結(jié)構(gòu)體) 不支持繼承,只有 類 支持繼承花竞;
- 沒有父類的類稱為 基類 (Swift 并沒有像OC/Java 那樣規(guī)定 :任何類 最終都要繼承于某個(gè)基類)
- 子類可以重寫父類的
下標(biāo)
骗卜、方法
、屬性
重寫必須加上override
關(guān)鍵字
-
1.2左胞、重寫實(shí)例 方法 和 下標(biāo)
class Animal { func speak() { print("Animal speak") } subscript(index: Int) -> Int { return index } } var animal: Animal animal = Animal() animal.speak() // 打涌懿帧: Animal speak print(animal[10]) // 打印: 10 class Cat:Animal { override func speak() { super.speak() print("Animal speak") } override subscript(index: Int) -> Int { return super[index] + 1 } } animal = Cat() animal.speak() print(animal[10]) // 打印 // Animal speak // Cat speak // 11
-
1.3烤宙、重寫類型 方法 和 下標(biāo)
- 被
class
修飾的 類型 方法遍烦、下標(biāo),允許
被子類重寫 - 被
static
修飾的 類型 方法躺枕、下標(biāo)服猪,不允許
被子類重寫
- 提示:被
static
修飾的 類型 方法、下標(biāo)拐云,不允許
被子類重寫
- 被
-
1.4罢猪、重寫屬性
- 子類可以將父類的屬性(存儲(chǔ)、計(jì)算)重寫為
計(jì)算屬性
- 子類
不可以
將父類屬性重寫為存儲(chǔ)屬性
- 只能重寫
var
屬性叉瘩,不能重寫let
屬性 - 重寫時(shí)膳帕,屬性名、類型要一致
- 子類重寫后的屬性權(quán)限 不能小于 父類屬性的權(quán)限
- 如果父類屬性是只讀的薇缅,那么子類重寫后的屬性可以是只讀的危彩、也可以是可讀寫的
- 如果父類屬性是可讀寫的,那么子類重寫后的屬性也必須是可讀寫的
- 子類可以將父類的屬性(存儲(chǔ)、計(jì)算)重寫為
-
1.5泳桦、重寫實(shí)例屬性
class Circle { var radius: Int = 0 var diameter: Int { set { print("Circle setDiameter") radius = newValue / 2 } get { print("Circle getDiameter") return radius * 2 } } } var circle:Circle circle = Circle() circle.radius = 6 // Circle getDiameter // 12 print(circle.diameter) // Circle setDiameter circle.diameter = 20 // 10 print(circle.radius) class SubCircle : Circle { override var radius: Int { set { print("SubCircle setRadius") super.radius = newValue > 0 ? newValue : 0 } get { print("SubCircle getRadius") return super.radius } } override var diameter: Int { set { print("SubCircle setDiameter") super.diameter = newValue > 0 ? newValue : 0 } get { print("SubCircle getDiameter") return super.diameter } } } circle = SubCircle() // SubCircle setRadius circle.radius = 6 // SubCircle getDiameter // Circle getDiameter // SubCircle getRadius // 12 print("--------------") print(circle.diameter) // SubCircle setDiameter // Circle setDiameter // SubCircle setRadius print("--------------") circle.diameter = 20 // SubCircle getRadius // 10 print("--------------") print(circle.radius)
-
1.6汤徽、重寫類型屬性
- 被 class 修飾的
計(jì)算型屬性,可以
被子類重寫 - 被 static 修飾的
類型屬性(存儲(chǔ)灸撰、計(jì)算)谒府,不可以
被子類重寫
被 static 修飾的 類型屬性(存儲(chǔ)、計(jì)算)浮毯,不可以被子類重寫 - 被 class 修飾的
-
1.7完疫、屬性觀察器
可以在子類中為父類屬性(除了
只讀計(jì)算屬性
、let
屬性)增加屬性觀察器-
舉例一
class Circle { var radius: Int = 1 } class SubCircle : Circle { override var radius: Int { willSet { print("SubCircle willSetRadius", newValue) } didSet { print("SubCircle didSetRadius", oldValue, radius) } } } var circle = SubCircle() // SubCircle willSetRadius 10 // SubCircle didSetRadius 1 10 circle.radius = 10
-
舉例二
class Circle { var radius: Int = 1 { willSet { print("Circle willSetRadius", newValue) } didSet { print("Circle didSetRadius", oldValue, radius) } } } class SubCircle : Circle { override var radius: Int { willSet { print("SubCircle willSetRadius", newValue) } didSet { print("SubCircle didSetRadius", oldValue, radius) } } } var circle = SubCircle() // SubCircle willSetRadius 10 // Circle willSetRadius 10 // Circle didSetRadius 10 // SubCircle didSetRadius 1 10 circle.radius = 10
-
舉例三
class Circle { var radius: Int { set { print("Circle setRadius", newValue) } get { print("Circle getRadius") return 20 } } } class SubCircle : Circle { override var radius: Int { willSet { print("SubCircle willSetRadius", newValue) } didSet { print("SubCircle didSetRadius", oldValue, radius) } } } var circle = SubCircle() // Circle getRadius // SubCircle willSetRadius 10 // Circle setRadius 10 // Circle getRadius // SubCircle didSetRadius 20 20 circle.radius = 10
-
舉例四
class Circle { class var radius: Int { set { print("Circle setRadius", newValue) } get { print("Circle getRadius") return 20 } } } class SubCircle : Circle { override static var radius: Int { willSet { print("SubCircle willSetRadius", newValue) } didSet { print("SubCircle didSetRadius", oldValue, radius) } } } Circle getRadius SubCircle willSetRadius 10 Circle setRadius 10 Circle getRadius SubCircle didSetRadius 20 20
1.8亲轨、final:被
final
修飾的的下標(biāo)趋惨、方法、屬性惦蚊,禁止被重寫器虾;被final
修飾的類禁止被繼承
二讯嫂、初始化
-
2.1、初始化器
類
兆沙、結(jié)構(gòu)體
欧芽、枚舉
都可以定義初始化器
-
類有2種初始化器:指定初始化器(designated initializer)、便捷初始化器(convenience initializer)
// 指定初始化器 init(parameters) { statements } // 便捷初始化器 convenience init(parameters) { statements }
每個(gè)類至少有一個(gè)指定初始化器葛圃,指定初始化器是類的主要初始化器
默認(rèn)初始化器總是類的指定初始化器
類偏向于少量指定初始化器千扔,一個(gè)類通常只有一個(gè)指定初始化器,可以有多個(gè)便捷初始化器
-
初始化器的相互調(diào)用規(guī)則
- 指定初始化器必須從它的直系父類調(diào)用指定初始化器 库正,也就是是能調(diào)用父類的指定初始化器
- 便捷初始化器必須從相同的類里調(diào)用另一個(gè)初始化器 曲楚,也就是不能調(diào)用父類 初始化器
- 便捷初始化器最終必須調(diào)用一個(gè)指定初始化器
-
2.2、初始化器的相互調(diào)用
Designated代表指定初始化器
分析:這一套規(guī)則保證了:使用任意初始化器褥符,都可以完整地初始化實(shí)例
- Swift在編碼安全方面是煞費(fèi)苦心龙誊,為了保證初始化過程的安全,設(shè)定了兩段式初始化喷楣、 安全檢查
- 兩段式初始化
- 第1階段:初始化所有存儲(chǔ)屬性
- <1>趟大、外層調(diào)用指定\便捷初始化器
- <2>、分配內(nèi)存給實(shí)例铣焊,但未初始化
- <3>逊朽、指定初始化器確保當(dāng)前類定義的存儲(chǔ)屬性都初始化
- <4>、指定初始化器調(diào)用父類的初始化器曲伊,不斷向上調(diào)用叽讳,形成初始化器鏈
- 第2階段:設(shè)置新的存儲(chǔ)屬性值
- <1>、從頂部初始化器往下熊昌,鏈中的每一個(gè)指定初始化器都有機(jī)會(huì)進(jìn)一步定制實(shí)例
- <2>绽榛、初始化器現(xiàn)在能夠使用self(訪問、修改它的屬性婿屹,調(diào)用它的實(shí)例方法等等) 3 最終,鏈中任何便捷初始化器都有機(jī)會(huì)定制實(shí)例以及使用self
-
2.3推溃、安全檢查
-
指定初始化器必須保證在調(diào)用父類初始化器之前昂利,其所在類定義的所有存儲(chǔ)屬性都要初始化完成,如下 代碼:
super.init(age: 2)
必須放到self.name = name
的后面class Person { var age:Int init(age:Int) { self.age = age } } class Son : Person { var name:String init(name:String) { self.name = name super.init(age: 2) } }
-
指定初始化器必須先調(diào)用父類初始化器铁坎,然后才能為繼承的屬性設(shè)置新值蜂奸,如下 代碼:
super.init(age: 2)
必須放到self.age = 20
的前面class Person { var age:Int init(age:Int) { self.age = age } } class Son : Person { var name:String init(name:String) { self.name = name super.init(age: 2) self.age = 20 } }
便捷初始化器必須先調(diào)用同類中的其它初始化器,然后再為任意屬性設(shè)置新值
初始化器在第1階段初始化完成之前硬萍,不能調(diào)用任何實(shí)例方法扩所、不能讀取任何實(shí)例屬性的值,也不能引用self
直到第1階段結(jié)束朴乖,實(shí)例才算完全合法祖屏,也就是可以用
self
-
-
2.4助赞、重寫:方法名、參數(shù)名以及 類型和父類的一樣
-
當(dāng)重寫父類的指定初始化器時(shí)袁勺,必須加上override(即使子類的實(shí)現(xiàn)是便捷初始化器)雹食,如下 代碼
class Person { var age:Int init(age:Int) { self.age = age } } class Son : Person { override init(age:Int) { super.init(age: 2) } }
-
如果子類寫了一個(gè)匹配父類便捷初始化器的初始化器,不用加上override 期丰,因?yàn)楦割惖谋憬莩跏蓟饔肋h(yuǎn)不會(huì)通過子類直接調(diào)用群叶,因此,嚴(yán)格來說钝荡,子類無法重寫父類的便捷初始化器街立,如下代碼,我們可以看到子類 和 父類 都有
convenience init(age:Int,no:Int)
埠通,子類的便利方法前不需要加override
,因?yàn)楸憷椒ㄊ菣M向調(diào)用的赎离,也就是只能調(diào)用自己類里面的方法class Person { var age:Int init(age:Int) { self.age = age } convenience init(age:Int,no:Int) { self.init(age:20) } } class Son : Person { init() { super.init(age: 20) } convenience init(age:Int,no:Int) { self.init() } }
-
-
2.5、自動(dòng)繼承
-
(1)植阴、如果子類沒有自定義任何指定初始化器蟹瘾,它會(huì)自動(dòng)繼承父類所有的指定初始化器 ,如下代碼:Son 會(huì)繼承Person的所有方法
class Person { var age:Int init(age:Int) { self.age = age } convenience init(age:Int,no:Int) { self.init(age:20) } } class Son : Person { }
(2)掠手、如果子類提供了父類所有指定初始化器的實(shí)現(xiàn)(要么通過方式1繼承憾朴,要么重寫),子類自動(dòng)繼承所有的父類便捷初始化器
-
(3)喷鸽、就算子類添加了更多的便捷初始化器众雷,這些規(guī)則仍然適用,如下
class Person { var age:Int init(age:Int) { self.age = age } convenience init(age:Int,no:Int) { self.init(age:20) } } class Son : Person { convenience init(age:Int,no:Int) { self.init(age:20) } func test() -> Void { print("測(cè)試") } } let son = Son(age: 20) son.test()
-
(4)、子類以便捷初始化器的形式重寫父類的指定初始化器做祝,也可以作為滿足規(guī)則2的一部分砾省,如下代碼
class Person { var age:Int init(age:Int) { self.age = age } convenience init(age:Int,no:Int) { self.init(age:20) } } class Son : Person { override init(age:Int) { super.init(age: age) } } // 調(diào)用:可以看到父類 的便利方法被繼承了下來 let son = Son(age: 10, no: 20)
-
-
2.6、required
用required修飾指定初始化器混槐,表明其所有子類都必須實(shí)現(xiàn)該初始化器(通過繼承或者重寫實(shí)現(xiàn))
-
如果子類重寫了required初始化器编兄,也必須加上required,不用加override
class Person { required init() { } init(age: Int) { } } class Student : Person { required init() { super.init() } }
-
2.7声登、屬性觀察器
-
父類的屬性在它自己的初始化器中賦值不會(huì)觸發(fā)屬性觀察器狠鸳,但在子類的初始化器中賦值會(huì)觸發(fā)屬性觀察器
class Person { var age: Int { willSet { print("willSet", newValue) } didSet { print("didSet", oldValue, age) } } init() { self.age = 0 } } class Student : Person { override init() { super.init() self.age = 1 // 觸發(fā)屬性監(jiān)聽器 } } // willSet 1 // didSet 0 1 var stu = Student()
-
-
2.8、可失敗的初始化器
-
類悯嗓、結(jié)構(gòu)體件舵、枚舉都可以使用init?定義可失敗初始化器 n 之前接觸過的可失敗初始化器
class Person { var name: String init?(name: String) { if name.isEmpty { return nil } self.name = name } }
之前接觸過的可失敗初始化器
var num = Int("123") public init?(_ description: String) enum Answer : Int { case wrong, right } var an = Answer(rawValue: 1)
-
不允許同時(shí)定義參數(shù)標(biāo)簽、參數(shù)個(gè)數(shù)脯厨、參數(shù)類型相同的可失敗初始化器和非可失敗初始化器铅祸,如下代碼,
init?
和init
是不被允許的class Person { var name: String init?(name: String) { if name.isEmpty { return nil } self.name = name } init(name: String) { self.name = name } } // 調(diào)用產(chǎn)生歧義合武,不知道調(diào)用的是哪個(gè) init var p1 = Person(name:"") var p2 = Person(name:"Tom")
可以用init!定義隱式解包的可失敗初始化器
可失敗初始化器可以調(diào)用非可失敗初始化器临梗,非可失敗初始化器調(diào)用可失敗初始化器需要進(jìn)行解包
-
如果初始化器調(diào)用一個(gè)可失敗初始化器導(dǎo)致初始化失敗涡扼,那么整個(gè)初始化過程都失敗,并且之后的代碼都停止執(zhí)行夜焦,如下代碼
class Person { var name:String init?(name:String) { if name.isEmpty { return nil } self.name = name } convenience init?() { self.init(name:"") // 失敗之后壳澳,后面的代碼就不再執(zhí)行 self.name = "Tom" // ....... } }
-
可以用一個(gè)非可失敗初始化器重寫一個(gè)可失敗初始化器,但反過來是不行的
class Person { var name:String init?(name:String) { if name.isEmpty { return nil } self.name = name } convenience init?() { self.init(name:"") // 失敗之后茫经,后面的代碼就不再執(zhí)行 self.name = "Tom" // ....... } } class Student : Person { override init(name: String) { } }
-
-
2.9巷波、反初始化器(deinit)
-
deinit
叫做反初始化器,類似于C++的析構(gòu)函數(shù)卸伞、OC中的dealloc方法抹镊,當(dāng)類的實(shí)例對(duì)象被釋放內(nèi)存時(shí),就會(huì)調(diào)用實(shí)例對(duì)象的deinit方法class Person { deinit { print("Person對(duì)象銷毀了") } }
deinit不接受任何參數(shù)荤傲,不能寫小括號(hào)垮耳,不能自行調(diào)用
父類的deinit能被子類繼承
子類的deinit實(shí)現(xiàn)執(zhí)行完畢后會(huì)調(diào)用父類的deinit
-
三、可選鏈(Optional Chaining)
如果可選項(xiàng)為nil遂黍,調(diào)用方法终佛、下標(biāo)、屬性失敗雾家,結(jié)果為nil
-
如果可選項(xiàng)不為nil铃彰,調(diào)用方法、下標(biāo)芯咧、屬性成功牙捉,結(jié)果會(huì)被包裝成可選項(xiàng);如果結(jié)果本來就是可選項(xiàng)敬飒,不會(huì)進(jìn)行再次包裝
class Car { var price = 0 } class Dog { var weight = 0 } class Person { var name: String = "" var dog: Dog = Dog() var car: Car? = Car() func age() -> Int { 18 } func eat() { print("Person eat") } subscript(index: Int) -> Int { index } } var person: Person? = Person() var age1 = person!.age() // Int var age2 = person?.age() // Int? var name = person?.name // String? var index = person?[6] // Int? if let _ = Person?.eat() { print("eat調(diào)用成功") } esle { print("eat調(diào)用失敗") }
-
如果多個(gè)
?
可以鏈接在一起,如果鏈中任何一個(gè)節(jié)點(diǎn)是nil
邪铲,那么整個(gè)鏈就會(huì)調(diào)用失敗,如下面的var price = person?.car?.price
无拗,當(dāng)person
為nil
的 時(shí)候就不會(huì)再調(diào)用car?
var dog = person?.dog // Dog? var weight = person?.dog.weight // Int? var price = person?.car?.price // Int?
-
可選鏈的使用
var scores = ["Jack": [86, 82, 84], "Rose": [79, 94, 81]] scores["Jack"]?[0] = 100 scores["Rose"]?[2] += 10 scores["Kate"]?[0] = 88 var num1: Int? = 5 num1? = 10 // Optional(10) var num2: Int? = nil num2? = 10 // nil var dict: [String : (Int, Int) -> Int] = [ "sum" : (+), "difference" : (-) ] var result = dict["sum"]?(10, 20) // Optional(30), Int?
提示
- 當(dāng)
scores["Jack"]
為nil的 時(shí)候就不會(huì)再去調(diào)用[0]
- num1? = 10 也一樣带到,當(dāng)num1為nil的時(shí)候,就不需要 10 再賦值
-
var dict: [String : (Int, Int) -> Int]
里面的(+)
和(-)
代表兩個(gè)整數(shù)的相加
或者相減
- 當(dāng)
四英染、協(xié)議(Protocol)
-
4.1阴孟、協(xié)議可以用來定義方法、屬性税迷、下標(biāo)的聲明,協(xié)議可以被枚舉锹漱、結(jié)構(gòu)體箭养、類遵守(多個(gè)協(xié)議之間用逗號(hào)隔開)
protocol Test1 {} protocol Test2 {} protocol Test3 {} class TestClass : Test1, Test2, Test3 {}
協(xié)議中定義方法時(shí)不能有默認(rèn)參數(shù)值
-
默認(rèn)情況下,協(xié)議中定義的內(nèi)容必須全部都實(shí)現(xiàn)(也有辦法辦到只實(shí)現(xiàn)部分內(nèi)容)
protocol Drawable { func draw() var x: Int { get set } var y: Int { get } subscript(index: Int) -> Int { get set } }
-
4.2哥牍、協(xié)議中的屬性
protocol Drawable { func draw() var x: Int { get set } var y: Int { get } subscript(index: Int) -> Int { get set } }
協(xié)議中定義屬性時(shí)必須用var關(guān)鍵字
實(shí)現(xiàn)協(xié)議時(shí)的屬性權(quán)限要不小于協(xié)議中定義的屬性權(quán)限
協(xié)議定義get毕泌、set喝检,用var存儲(chǔ)屬性或get、set計(jì)算屬性去實(shí)現(xiàn)
-
協(xié)議定義get撼泛,用任何屬性都可以實(shí)現(xiàn)
class Person : Drawable { var x: Int = 0 let y: Int = 0 // 因?yàn)槭侵蛔x get ,所以用 let 也可以 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 } } }
-
4.3挠说、static、class
為了保證通用愿题,協(xié)議中必須用static定義類型方法损俭、類型屬性、類型下標(biāo)潘酗,因?yàn)?class 定義的只能在類里面使用杆兵,static定義的在類 、枚舉仔夺、結(jié)構(gòu)體 里面都可以使用protocol Drawable { static func draw() } class Person1 : Drawable { class func draw() { print("Person1 draw") } } class Person2 : Drawable { static func draw() { print("Person2 draw") } }
4.4琐脏、mutating
-
只有將協(xié)議中的實(shí)例方法標(biāo)記為mutating
才允許結(jié)構(gòu)體、枚舉的具體實(shí)現(xiàn)修改自身內(nè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 } }
-
4.5、init
-
協(xié)議中還可以定義初始化器init惰蜜,非final類實(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)的初始化器昂拂,剛好是重寫了父類的指定初始化器 ,那么這個(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) } }
提示:required 是協(xié)議的要求政钟,非final類實(shí)現(xiàn)時(shí)必須加上required;override 是重寫了父類的指定初始化器
-
-
4.6樟结、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) {} }
-
4.7玫镐、協(xié)議的繼承
一個(gè)協(xié)議可以繼承其他協(xié)議protocol Runnable { func run() } protocol Livable : Runnable { func breath() } class Person : Livable { func breath() {} func run() {} }
-
4.8倒戏、協(xié)議組合
協(xié)議組合,可以包含1個(gè)類類型(最多1個(gè))protocol Livable {} protocol Runnable {} class Person {} // 接收Person或者其子類的實(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或者其子類的實(shí)例 func fn3(obj: Person & Livable & Runnable) {} typealias RealPerson = Person & Livable & Runnable // 接收同時(shí)遵守Livable、Runnable協(xié)議葛闷、并且是Person或者其子類的實(shí)例 func fn4(obj: RealPerson) {}
-
4.9憋槐、CaseIterable
讓枚舉遵守CaseIterable
協(xié)議,可以實(shí)現(xiàn)遍歷枚舉值enum Season : CaseIterable { case spring, summer, autumn, winter } let seasons = Season.allCases // 返回?cái)?shù)組 print(seasons.count) // 4 for season in seasons { print(season) } // spring summer autumn winter
提示:Season.allCases 等價(jià)于 [Season.spring,Season. summer,Season. autumn,Season. winter]
-
4.10淑趾、CustomStringConvertible
遵守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
- print調(diào)用的是
-
4.11近范、Any、AnyObject
Swift提供了2種特殊的類型:Any旷赖、AnyObject
Any:可以代表任意類型(枚舉顺又、結(jié)構(gòu)體、類等孵,也包括函數(shù)類型)
-
AnyObject:可以代表任意類類型(在協(xié)議后面寫上: AnyObject代表只有類能遵守這個(gè)協(xié)議)
在協(xié)議后面寫上: class也代表只有類能遵守這個(gè)協(xié)議
var stu: Any = 10 stu = "Jack" stu = Student()
創(chuàng)建1個(gè)能存放任意類型的數(shù)組
// var data = Array<Any>() var data = [Any]() data.append(1) data.append(3.14) data.append(Student()) data.append("Jack") data.append({ 10 })
-
4.12稚照、is、as?俯萌、as!果录、as
is用來判斷是否為某種類型,as用來做強(qiáng)制類型轉(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 (stu as? Student)?.study() // 沒有調(diào)用study stu = Student() (stu as? Student)?.study() // Student study 提示:第一個(gè)問號(hào)代表轉(zhuǎn)換可能成功也可能失敗咐熙,返回可選類型弱恒;第二個(gè)問號(hào)是可選鏈 (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 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
-
4.13、X.self棋恼、X.Type返弹、AnyClass
X.self 是一個(gè)元類型(metadata)的指針,metadata存放著類型相關(guān)信息
-
X.self 屬于 X.Type 類型
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
-
4.14爪飘、元類型的應(yīng)用
-
元類型的應(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]))
-
元類型的應(yīng)用二
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é)果可以看得出來义起,Swift還有個(gè)隱藏的基類:Swift._SwiftObject ,可以參考Swift源碼
-
-
4.15师崎、Self
-
Self 代表當(dāng)前類型
class Person { var age = 1 static var count = 2 func run() { print(self.age) // 1 print(Self.count) // 2 } }
-
Self 一般用作返回值類型默终,限定返回值跟方法調(diào)用者必須是同一類型(也可以作為參數(shù)類型)
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())
-