讀古今文學網 > iOS編程基礎:Swift、Xcode和Cocoa入門指南 > 10.6 NSObject揭秘 >

10.6 NSObject揭秘

由於每個Objective-C類都繼承自NSObject,因此我們有必要花些時間瞭解一下NSObject。NSObject的構造方式很複雜:

·它定義了一些本地類方法與實例方法,主要與實例化基本功能及方法發送和解析相關。(參見NSObject Class Reference。)

·它使用了NSObject協議。該協議聲明了與內存管理相關的實例方法、實例與類之間的關係以及內省機制。由於所有的NSObject協議方法都是必需的,NSObject類會將其全部實現出來。(參見NSObject Protocol Reference。)在Swift中,NSObject協議叫作NSObjectProtocol,目的在於避免命名衝突。

·它實現了與NSCopying、NSMutableCopying與NSCoding協議相關的便捷方法,但卻沒有正式使用這些協議。NSObject有意不使用這些協議的原因在於這會導致所有其他的類都要使用該協議,但這麼做是錯誤的。多虧了該架構,如果某個類使用了其中一個協議,那麼你就可以調用相應的便捷方法。比如,NSObject實現了copy實例方法,這樣你就可以在任何實例上調用copy了,但如果實例所屬的類沒有使用NSCopying協議並實現copyWithZone:,那就會導致應用崩潰。

·有大量方法通過NSObject上的20多個類別注入了NSObject中,它們散落在各種頭文件中。比如,awakeFromNib(參見第7章)來自於NSObject上的UINibLoadingAdditions類別,它聲明在UINibLoading.h中。

·class對象也是個對象。因此,所有Objective-C類(Class類型的對象)都繼承自NSObject。這樣,NSObject所定義的任何實例方法都能以類方法的形式在class對像上調用!比如,respondsToSelector:是NSObject定義的一個實例方法,但也可以將其看作類方法並發送給class對象。

程序員所面臨的一個問題就是Apple的文檔在分類上過於死板。如果想瞭解某個對象,那麼就不要管該對象的方法來自於何處;只要知道方法是什麼就行。但Apple通過來源對方法進行了區分。雖然NSObject是根類,也是最重要的類,所有其他的類都繼承自它,但沒有一頁文檔概述了所有這些方法。相反,你需要同時查詢NSObject Class Reference與NSObject Protocol Reference,還有NSCopying、NSMutableCopying與NSCoding協議的文檔頁(為了理解它們如何與NSObject定義的方法進行交互),你還要提供每個NSObject實例方法的類方法版本!

還有一些方法通過類別注入了NSObject中。一些通用方法會在NSObject類文檔頁面中進行說明;比如,awakeAfterUsingCoder:來自於聲明在單獨頭文件中的類別,不過它卻在NSObject文檔中進行了說明,因為它是個類方法,也是個全局方法,你可以隨時使用它。其他一些則是使用受限的委託方法(其實是非正式協議),不需要集中說明;比如,animationDidStart:記錄在CAAnimation類中,因為只有在使用CAAnimation時你才需要瞭解它。不過,每個對象都可以響應awakeFromNib,它對於你所編寫的每個應用都是至關重要的,因此需要單獨學習;對其的介紹在NSObject UIKit Additions Reference中,你可能找不到!同樣,所有的鍵值編碼方法(參見本章前面的介紹)與鍵值觀測方法(參見第11章)都如此。

使出渾身解數找出了所有的NSObject方法後,你會發現它們可以很自然地劃分為幾類:

創建、銷毀與內存管理

用於創建實例的方法,如alloc與copy,以及用於瞭解對像生命週期中發生了哪些事情的方法,如initialize與dealloc,還有用於管理內存的方法。

類關係

用於獲取對像所屬類與繼承關係的方法,如superclass、isKindOfClass:與isMemberOfClass:。

對像內省與比較

用於確定假如向某個對象發送某條消息時將會發生什麼事情的方法,如respondsToSelector:;用於將對像表示為字符串(description)與對像比較(isEqual:)的方法。

消息響應

用於確定當向某個對象發送某條消息時將會發生什麼的方法,如doesNotRecognize-Selector:。如果感興趣,請參見Objective-C Runtime Programming Guide。

消息發送

用於動態發送消息的方法。比如,performSelector:接收一個選擇器作為參數,並會將其發送給一個對象,告訴該對像執行這個選擇器。這看起來與將該消息發送給這個對象是一樣的,不過如果直到運行期才知道所發送的消息該怎麼做呢?此外,performSelector:的各變種可以在指定的線程上發送消息,或是經過一段時間後再發送消息(performSelector:withObject:afterDelay:等)。

performSelector...方法是Swift 2.0新引入的。之前,在Swift中是無法調用它的;我經常在Objective-C中使用它們,不過將代碼轉換為Swift迫使我尋找解決問題的其他方法,我發現在沒有它們的情況下我也能很好地進行管理。