Swift3.0 - 真的很簡單
Swift3.0 - 數(shù)據(jù)類型
Swift3.0 - Array
Swift3.0 - 字典
Swift3.0 - 可選值
Swift3.0 - 集合
Swift3.0 - 流控制
Swift3.0 - 對象和類
Swift3.0 - 屬性
Swift3.0 - 函數(shù)和閉包
Swift3.0 - 初始化和釋放
Swift3.0 - 協(xié)議protocol
Swift3.0 - 類和結構體的區(qū)別
Swift3.0 - 枚舉
Swift3.0 - 擴展
Swift3.0 - 下標
Swift3.0 - 泛型
Swift3.0 - 異常錯誤
Swift3.0 - 斷言
Swift3.0 - 自動引用計數(shù)(strong,weak,unowned)
Swift3.0 - 檢測API
Swift3.0 - 對象的標識
Swift3.0 - 注釋
Swift3.0 - 元類型
Swift3.0 - 空間命名
Swift3.0 - 對象判等
Swift3.0 - 探究Self的用途
Swift3.0 - 類簇
Swift3.0 - 動態(tài)調(diào)用對象(實例)方法
Swift3.0 - 文本輸出
Swift3.0 - 黑魔法swizzle
Swift3.0 - 鏡像
Swift3.0 - 遇到的坑
注意
1.系統(tǒng)要求存儲屬性必須初始化
2.可選值可以不用初始化,如果不初始化值,系統(tǒng)默認用nil初始化它
3.如果非可選類型存儲屬性不設置默認值,則必須在初始化方法中對其進行初始化
4.類必須自己寫初始化方法,初始化沒有默認值的非可選存儲屬性
5.結構體系統(tǒng)默認會添加初始化方法,當然自己也可以自定義
6.子類如果沒有自己的初始化方法,系統(tǒng)默認使用父類的初始化方法,一旦有了自己的初始化方法,或者重寫了父類的初始化方法,則父類的所有初始化不能被子類調(diào)用
7.你可以給子類添加和父類相同的初始化方法,但需要加上override 修飾
8.重寫父類的convenience修飾的方便初始化方法,不需要加override 關鍵字
- 指定初始化(Designated)
1.可以有多個指定初始化方法
class Person{
var name:String
var age:Int = 0
var weight:Double = 0.0
var height:Double = 0.0
init(name:String,height:Double) {
self.name = name
self.height = height
}
init(name:String) {
self.name = name
}
}
- 方便初始化(convenience)
記住:
1.在同一個類,使用convenience修飾的初始化方法必須調(diào)用一個其他初始化方法
2.convenience 必須最終調(diào)用一個指定的初始化方法
3.當子類繼承父類時,子類的初始化方法,必須調(diào)用父類的指定初始化方法,不能調(diào)用使用convienience修飾的方便初始化方法
4.在swift3.0 初始化中,可以自己調(diào)用自己的初始化方法,系統(tǒng)不會檢測出來,在創(chuàng)建convenience方便初始化方法的時候,需要小心,千萬不要相互引用了
實例代碼
// 父類
class Person{
var name:String
var age:Int = 0
var weight:Double = 0.0
var height:Double = 0.0
init(name:String,height:Double) {
self.name = name
self.height = height
}
init(name:String) {
self.name = name
}
// 1.定義一個convenience 修飾的初始化方法,如果在同一個類中必須 調(diào)用其他沒有convenience修飾的初始化方法
convenience init(name:String,age:Int){
self.init(name:name)
self.age = age
}
// 2.如果定義兩個或者多個convenience 修飾的初始化,只需要調(diào)用任意一個初始化方法即可滿足語法要求
convenience init(name:String,age:Int,weight:Double){
self.init(name:name,age:age)
self.weight = weight
}
}
// 子類
class Man: Person {
var address:String = ""
init(name:String,age:Int,weight:Double) {
// 3.必須調(diào)用父類指定初始化方法,不能調(diào)用convenience 修飾的方便初始化方法
super.init(name: name)
}
}
- 類初始化的過程
第一階段
1.調(diào)用指定初始化方法或者方便初始化
2.給新的實例分配內(nèi)存,但內(nèi)存還沒有初始化
3.指定初始化方法確定所有存儲屬性都被初始化,內(nèi)存這個時候被初始化
4.然后去調(diào)用父類的指定初始化方法,任務和調(diào)用自己指定初始化方法相同
5.繼續(xù)在類繼承鏈中指定上述過程,直到達到鏈的頂部為止
6.當?shù)酵瓿苫惖某跏蓟臅r候,實例的初始化算是完成了,我們的第一階段完成
第二階段
1.可以對屬性值進行修改
2.可以調(diào)用對象方法
- 重寫初始化方法
先看一個例子
// 父類
class Person{
var name:String
var age:Int = 0
var weight:Double = 0.0
var height:Double = 0.0
init(name:String,height:Double) {
self.name = name
self.height = height
}
init(name:String) {
self.name = name
}
convenience init(name:String,age:Int,weight:Double){
self.init(name:name)
self.age = age
self.weight = weight
}
}
// 子類
class Man: Person {
var address:String = ""
// 重寫父類指定初始化方法
override init(name:String) {
super.init(name: name)
}
// 重寫父類convenience 修飾的初始化方法 不需要添加override 關鍵字
init(name:String,age:Int,weight:Double){
super.init(name: name)
}
// 創(chuàng)建自己的初始化方法
convenience init(name:String,age:Int,weight:Double,address:String){
self.init(name: name)
self.address = address
self.age = age
self.weight = weight
}
}
總結:
1.創(chuàng)建新的指定初始化方法,必須調(diào)用父類的指定初始化方法 (Designated)
2.創(chuàng)建新的方便初始化方法,必須調(diào)用自己的指定初始化方法,或者方便初始化方法(convenience)
3.重寫父類的指定初始化方法,在方法名前加override ,然后調(diào)用父類的指定初始化方法
4.重寫父類的方便初始化方法(convenience) 不需要加override 或者convenience 關鍵字,調(diào)用父類的指定初始化方法,如果加上convenice關鍵字,則必須調(diào)用自己的初始化方法
5.如果子類沒有初始化方法,系統(tǒng)會自動繼承父類的初始化方法
6.初始化調(diào)用父類初始化時,需要先初始化子類的存儲屬性,但是如果是convenience修飾的初始化方法,要先調(diào)用自己的其他初始化方法,然后再給自己的存儲屬性賦值
- 創(chuàng)建一個可能失敗的初始化方法
注意:
1.不能在重寫的初始化方法改為可能失敗的初始化方法
2.不能使用相同的參數(shù)定義一個可能失敗的初始化方法和不會失敗的初始化方法
3.可能失敗的類型可以重寫為不會失敗類型
4.init? 可以被重寫為init!,當然可逆也是可以的
5.init?和init! 都可以被重寫為init
例子1
class Man: Person {
var address:String = ""
convenience init?(name:String,age:Int,weight:Double,address:String){
if name == "" {
return nil
}
self.init(name: name)
self.address = address
self.age = age
self.weight = weight
}
}
例子2
enum TemperatureUnit {
case kelvin, celsius, fahrenheit
init?(symbol: Character) {
switch symbol {
case "K":
self = .kelvin
case "C":
self = .celsius
case "F":
self = .fahrenheit
default:
return nil
}
}
}
例子2: 子類將父類可能失敗的初始化方法,修改為不會失敗的類型
class Animal{
var name:String
init?(name:String) {
if name.isEmpty {
return nil
}
self.name = name
}
}
對于可能出現(xiàn)空值的對象或者其他類型,在使用之前必須進行驗證
enum TemperatureUnit: Character {
case kelvin = "K", celsius = "C", fahrenheit = "F"
}
let fahrenheitUnit = TemperatureUnit(rawValue: "F")
if fahrenheitUnit != nil {
print("This is a defined temperature unit, so initialization succeeded.")
}
需求: 創(chuàng)建一個文件類,文件名字可以為nil,但是不能為空即""
寫法一:
class Document {
var name:String?
init?(name:String?){
if name != nil && name!.isEmpty{
return nil
}
self.name = name
}
}
分析這種寫法
只有一種初始化方法,也就是說,不管有沒有名字,我們都需要給初始化傳個參數(shù),顯然這樣不合理,目標不明確
寫法二:
class Document {
var name: String?
init() {} // 專門初始化name為 nil的情況
init?(name: String) { // 傳入名字 ,肯定不為nil ,只需要判斷是否為空即可
if name.isEmpty { return nil }
self.name = name
}
}
疑問: init! 和init? 被重寫為init 的意義何在?
暫時沒想到
- 需要的初始化方法(required)
注意
1.子類必須重寫父類用required修飾的方法
2.可以和convenience 組合使用
a-1.父類要求一個初始化方法被重寫
class Person{
var name:String
var age:Int = 0
var weight:Double = 0.0
var height:Double = 0.0
init(name:String,height:Double) {
self.name = name
self.height = height
}
init(name:String) {
self.name = name
}
// 要求子類必須重寫這個方法
required convenience init(name:String,age:Int,weight:Double){
self.init(name:name)
self.age = age
self.weight = weight
}
}
a-2.子類重寫父類要求的初始化方法
class Man: Person {
var address:String = ""
// 重寫父類要求的初始化convenience 修飾的初始化方法 不需要添加override 關鍵字
required init(name:String,age:Int,weight:Double){
super.init(name: name)
}
}
- 反初始化(deinit)
注意:
1.deinit 在對象被釋放前調(diào)用
寫法很簡單
deinit {
}
蘋果文檔有個例子簡單講解了一下它的重要性
例子: 有一個賭徒在銀行存了10_000 元,賭徒從銀行取錢然后去賭博,當賭徒對象釋放了就將錢全部存到銀行
class Bank {
static var coinsInBank = 10_000
static func distribute(coins numberOfCoinsRequested: Int) -> Int {
let numberOfCoinsToVend = min(numberOfCoinsRequested, coinsInBank)
coinsInBank -= numberOfCoinsToVend
return numberOfCoinsToVend
}
static func receive(coins: Int) {
coinsInBank += coins
}
}
賭徒類
class Player {
var coinsInPurse: Int
init(coins: Int) {
coinsInPurse = Bank.distribute(coins: coins)
}
func win(coins: Int) {
coinsInPurse += Bank.distribute(coins: coins)
}
deinit {
Bank.receive(coins: coinsInPurse)
}
}
執(zhí)行
var playerOne: Player? = Player(coins: 100)
playerOne!.win(coins: 2_000)
playerOne = nil