Property(屬性)
屬性將值與特定的類、結(jié)構(gòu)體或枚舉聯(lián)系起來。Stored屬性將常量或變量存儲作為實(shí)例的一部分,而computed屬性計(jì)算而不是存儲值。Computed屬性是類、結(jié)構(gòu)體或枚舉提供的,Stored屬性只有類或結(jié)構(gòu)體提供 。
Stored或Computed屬性通常與特定類型的實(shí)例相關(guān)聯(lián)。但是,屬性也可以與類型本身相關(guān)聯(lián)。這樣的屬性稱為type property。
最簡單的情況下,stored property就是作為一個類、結(jié)構(gòu)體的實(shí)例的一部分而存儲。
必須將一個lazy屬性聲明為var,因?yàn)樗闹悼赡茉趯?shí)例初始化完成后才能獲得。constant要求在初始化完成時就已經(jīng)有值,因此不能是lazy的。
Lazy屬性在初始化依靠于外部因素時比較有用,如果一個屬性的值要復(fù)雜計(jì)算開銷很大時,使用lazy也是很合適的
注意,lazy屬性的初始化過程不是線程安全的!
Objective C中提供了兩個方式來存儲值和引用,除了屬性,你還可以使用instance variable as a backing store。
Swift將這些概念統(tǒng)一到了一個單獨(dú)的屬性聲明中。一個Swift屬性沒有對應(yīng)的instance variable,屬性的backing store不能直接被訪問。這種方式避免了值在不同上下文如何訪問的困惑。屬性的所有信息,都作為類型定義的一部分在同一個位置定義。
除了Stored屬性,類、結(jié)構(gòu)體和枚舉還提供computed屬性,它實(shí)際上不存儲值,只是提供一個getter方法(setter方法可選)來間接獲取和設(shè)置其它屬性的值。
如果將一個有observer的屬性作為函數(shù)的in-out參數(shù)傳遞,那么willSet和didSet總會被調(diào)用。因?yàn)閕n-out參數(shù)的copy-in、copy-out內(nèi)存模型使得函數(shù)在結(jié)束時總會回寫屬性的值。
關(guān)于全局和局部變量
全局的變量或常量總是惰性計(jì)算的,類似于惰性存儲的屬性,不同的是全局的常量和變量不需要聲明為lazy
局部常量和變量永遠(yuǎn)不會惰性計(jì)算
Type Property
Type屬性必須給初值,因?yàn)闆]有initializer來初始化它。Stored type屬性第一次訪問是惰性的,它們能保證只初始化一次。
繼承
Swift的類沒有繼承一個通用的基類。如果沒有給定義的類指定superclass的話,那么你定義的這個類就是自己的基類。
Overriding
- 重寫Property Getters 和 Setters
可以通過提供自定義的getter或setter重寫任何繼承的屬性,不管這個屬性是stored還是computed屬性。子類并不是知道繼承屬性是stored還是computed,它只知道屬性的類型和名字。
可以通過提供getter和setter來重寫只讀屬性為可讀寫的屬性。但是,不能將可讀寫的屬性重寫為只讀的。
如果你提供了屬性setter方法的重寫,你也必須提供getter方法。如果你不想在getter方法內(nèi)修改繼承屬性的值,只需要在方法內(nèi)簡單地返回super.someProperty。
- 重寫Property Observers
不能給繼承的常量stored屬性或者只讀computed屬性添加observers。這些屬性的值是不能修改的
同時,你不能同時重寫一個屬性的setter和observer。如果你想觀測屬性值的改變,同時也想提供自定義的setter方法,你只需要在setter方法中觀測值的改變就好了。
3.重寫方法
禁止Overrides
可以通過設(shè)置method、property或subscript為final來禁止重寫??梢詫lass標(biāo)記為final,這樣任何類都不能繼承這個類。
Structure也支持class的很多行為,比如methods和initializer,最重要的一點(diǎn)區(qū)別就是structure傳遞的時候總是被拷貝的,但是class是通過引用。Structure適合一些輕量級的不需要繼承和類型轉(zhuǎn)換的數(shù)據(jù)結(jié)構(gòu)。
Protocol
A protocol defines a blueprint of methods,properties and other requirements that suit a particular task or piece of functionality.
Protocol可以被class、structure和enumeration實(shí)現(xiàn)
protocol ExampleProtocol{
var simpleDescription:String {get}
func adjust()
}
{get}表示這個屬性是只讀的,不能被修改
Protocol are first-class types,which means they can be treated like other named types.即協(xié)議也跟普通的數(shù)據(jù)類型一樣被對待。比如,也可以創(chuàng)建一個協(xié)議的數(shù)組等。
ARC
類間相互引用的三種情況
- 兩個屬性都可以是nil,互相引用時可能會導(dǎo)致強(qiáng)引用循環(huán)。這個場景最好用weak reference進(jìn)行解決(人和住宅的例子)
- 兩個屬性,一個可以是nil,另一個不能為nil,這種場景下最好用unowned reference(人和信用卡的例子)
- 兩個屬性都必須不為nil時。這種情況下,一個類使用unowned reference,另一個使用implicit unwrapped optional。
Initialization
Classes和Structures必須在實(shí)例創(chuàng)建時給所有的stored屬性賦初始值??梢栽趇nitializer中賦值,也可以在聲明屬性時設(shè)置默認(rèn)值。
當(dāng)設(shè)置stored屬性默認(rèn)值或在initializer中初始化時,屬性的observer不會被調(diào)用
Initializer delegation:Initializer可以調(diào)用其他的initializer來完成初始化過程,避免重復(fù)的代碼
Value types(structures和enumerations)不支持繼承,所以initialize delegate只是調(diào)用自己定義的其他initializer。
如果你想同時用默認(rèn)的default initializer和memberwise initializer、自定義的initializer來初始化,那么可以將自定義的initializer放到extension中。
Designated Initializer And Convenience Initializer
Designated Initializer是類的主要初始化方法,它完全初始化所有的屬性,調(diào)用superclass的initializer來傳遞superclass chain。每個類都至少要有一個。
Convenience Initializer是次要的,支持性的initializer??梢远x它來調(diào)用designated initializer(設(shè)置某些屬性為默認(rèn)值)。
Initializer Delegation For Class Types
規(guī)則1
Designated initializer必須調(diào)用 immediate superclass的designated initializer
規(guī)則2
Convenience initializer必須調(diào)用同一個類的initializer
規(guī)則3
Convenience initializer必須調(diào)用designated initializer

簡單的方式,
- Designated initializer必須delegate up
- Convenience initializer必須delegate cross
Two-Phase Initialization
Swift的編譯器為了確保two-phase initialization正確執(zhí)行而進(jìn)行一些安全性檢查。
Safety Check1
Designated initializer必須確保在initializer傳遞到superclass前所有的屬性都已經(jīng)初始化了。
只要所有的stored屬性都初始化,就認(rèn)為這個對象的內(nèi)存已經(jīng)完全初始化了。所以,designated initializer必須確保在傳遞初始化鏈前所有的屬性都初始化。
Safety Check2
Designated initializer必須在給繼承屬性賦值前調(diào)用superclass initializer,如果不這么做,賦值會被superclass的initializer覆蓋。
Safety Check3
Convenience Initializer必須在給任何屬性賦值前調(diào)用其他的initializer。如果不這么做,賦值會被designated initializer覆蓋。
Safety Check4
Initializer不能調(diào)用任何實(shí)例方法,讀取任何實(shí)例屬性,或引用self,直到initializer的first phase完成。
Swift初始化主要分兩步,第一步給每個stored屬性賦一個初始值,一旦每個屬性的初始值確定,第二個步驟就開始了,在實(shí)例被使用之前,每個類都有機(jī)會自定義stored屬性。
Swift的兩步初始化過程與OC的類似。不同點(diǎn)在于第一步時,OC給每個屬性賦zero或null。Swift的初始化更靈活,可以有自定義的初始值。
Phase 1
- Initializer被調(diào)用
- 分配內(nèi)存,但內(nèi)存還未初始化
- designated intializer確認(rèn)所有的stored屬性都有值,這些屬性的內(nèi)存開始初始化
- designated initializer交給superclass的initializer給它自己的屬性進(jìn)行同樣的任務(wù)
- 繼承鏈進(jìn)行傳遞
- 繼承鏈到頂之后,鏈上的最后一個類確保所有的stored屬性都有值,實(shí)例的內(nèi)存被認(rèn)為完全初始化了
Phase 2
- 從繼承鏈往回遍歷,每個designated initializer都有機(jī)會自定義實(shí)例。initializer可以訪問self,修改屬性,調(diào)用實(shí)例方法等等
- 最后,任何的convenience initializer可以選擇自定義實(shí)例
Swift的subclass默認(rèn)是不繼承superclass的initializer的。但是特定情況下superclass的initializer會被繼承。假設(shè)subclass引入的新的屬性都有默認(rèn)值,那么會應(yīng)用下面規(guī)則:
規(guī)則1
如果subclass沒有定義任何的initializer,它自動繼承superclass所有的designated initializer。
規(guī)則2
如果subclass提供了所有的designated initializer的實(shí)現(xiàn)(通過規(guī)則1或自定義),那么它自動繼承所有的convenience initializer。(以convenience的方式也可以)
不能定義相同參數(shù)和名稱的failable、nonfailable initializer
failable initializer創(chuàng)建一個optional值。
如果使用closure來初始化屬性,牢記在closure執(zhí)行完畢之前其余的實(shí)例都沒有被初始化。這意味著在closure中不能訪問其他任意屬性,即使它有默認(rèn)值。也不能使用self屬性,或調(diào)用實(shí)例方法。
Closure
Global和nested function其實(shí)是特殊形式的closure。Closure有三種形式:
- Global function,有名稱,不捕獲任何值
- Nested function,有名稱,捕獲包含它的function內(nèi)的值
- Closure,沒名稱,捕獲上下文的值
Trailing Closure
如果closure作為function的最后一個參數(shù),并且closure定義非常長,那么可以使用trailing closure的技巧,將closure定義寫在函數(shù)的外面。
func someFunctionThatTakesAClosure(closure: () -> Void) {
// function定義
}
// here's how you call this function without using a trailing closure:
func someFunctionThatTakesAClosure({
// closure定義
})
// here's how you call this function with a trailing closure instead:
func someFunctionThatTakesAClosure() {
// trailing closure's 定義
}
Nonescaping Closures
當(dāng)closure作為function的參數(shù),但是在function返回之后才被調(diào)用,就說這個closure escape a function。
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
print(customersInLine.count)
// Prints "5"
##Autoclosures
Autoclose是一個包含表達(dá)式、作為函數(shù)參數(shù)的的closure。它不包含任何參數(shù),當(dāng)調(diào)用時,它返回表達(dá)式的值。Autoclosure能延遲evaluation。
//Autoclosure,此時closure不執(zhí)行
let customerProvider = { customersInLine.removeAtIndex(0) }
print(customersInLine.count)
// Prints "5"
//此時closure被真正調(diào)用
print("Now serving \(customerProvider())!")
// Prints "Now serving Chris!"
print(customersInLine.count)
// Prints "4"
- AnyObject可以表示任意類的實(shí)例
- Any可以表示任何類型的實(shí)例,包括函數(shù)類型
Extensions
Extensions可以給現(xiàn)有的class、structure、enumeration或protocol添加新的功能。與OC中的category類似,但是沒有名字。
Extensions可以:
- 添加computed實(shí)例屬性和類型屬性
- 定義實(shí)例方法和類方法
- 提供新的initializer
- 定義subscript
- 定義和使用新的nexted types
- 讓現(xiàn)有類型服從某一協(xié)議