2013-05-15 93 views
0

背景:iOS向後兼容性 - 不存在類的alloc/init

假設我正在開發使用iOS 6 SDK的應用程序。我有我的部署目標設置到iOS 5 然後我可以使用的功能,從6,但爲了保持與5的兼容性,你必須在你的代碼進行一些檢查:

// method only available from 6, class of someObj existed in 5 
if (someObj respondToSelector:@selector(aMethod)) { 
    [someObj aMethod]; 
} 

或者

// entire class only available from 6 
if (NSStringFromClass([SKStoreProductViewController class]) != nil) { 
    SKStoreProductViewController *store = [[SKStoreProductViewController alloc] init]; 
} 

到目前爲止這麼好。就我所知,這是做事的標準方式。但我今天發現,對於新的類的例子,如果我只是嘗試並沒有任何檢查地從該類中分配/初始化一個對象 ,它不會在iOS 5上崩潰,而我會預期它會返回而不是返回空值。

// run this on an iOS 5 device 
NSLog(@"%@", [UICollectionView alloc] init]); 

爲什麼這不會導致iOS 5崩潰?我想這與 連接器的工作方式有關,但是我會期望崩潰,因爲該版本中不存在該符號。

第二個問題是:如果正常測試是使用NSStringFromClass方法,這意味着您可以將+類方法發送到一個不存在的類,它將返回null - 爲什麼/如何工作?

最後,我注意到我可以創建一個ViewController,它採用一個只在iOS 6中定義的協議,並且它不會導致5的問題。

回答

2

此行爲歸因於NS_CLASS_AVAILABLE宏。這個宏已經在大多數(全部)UIKit類中實現,並且對於不可用的類將返回nil。這使您可以檢查一類在特定的iOS版本的代碼存在:

if ([UICollectionView class]) { 
    // class exists, must be iOS6+ 
} 

現在,你的[[UICollectionView alloc] init]呼叫在無類,這將始終返回零一類方法調用。

要回答你的第二個問題,檢查類存在的正確方法是檢查類是否爲零,如上所述。 NSStringFromClass不再需要。

因此,問題3.我也對此感到驚訝,但它似乎將協議對象直接編譯到二進制文件中。在使用最新的SDK進行編譯時,代碼編譯良好,並且在尚未引入協議的SDK版本上運行時協議將可用,因爲不需要鏈接到缺少的類。這意味着Protocol對象將是有效的,無論您運行的是哪個iOS版本,該類都將正確響應conformsToProtocol:而不會出現任何問題。在編譯後的二進制文件中使用otool -l就可以很容易地看到這個文件,它將顯示類和它們的方法符合的協議。協議本身似乎生活在一個名爲__objc_protolist的部分。對於符合UICollectionViewDelegate和DataSource類輸出如下所示:

000050a4 0x5cf4 
      isa 0x5d08 
    superclass 0x0 
     cache 0x0 
     vtable 0x0 
      data 0x5b30 (struct class_ro_t *) 
        flags 0x80 
      instanceStart 156 
      instanceSize 156 
       ivarLayout 0x0 
        name 0x4a0f TTViewController 
       baseMethods 0x5b10 (struct method_list_t *) 
      entsize 12 
      count 2 
       name 0x3eb8 viewDidLoad 
      types 0x4955 [email protected]:4 
       imp 0x2620 
       name 0x3ec4 didReceiveMemoryWarning 
      types 0x4955 [email protected]:4 
       imp 0x2670 
      baseProtocols 0x5ad8 
         count 2 
       list[0] 0x5da0 (struct protocol_t *) 
        isa 0x0 
       name 0x4997 UICollectionViewDelegate 
      protocols 0x5304 
      instanceMethods 0x0 (struct method_list_t *) 
      classMethods 0x0 (struct method_list_t *) 
     optionalInstanceMethods 0x5310 
     optionalClassMethods 0x0 
      instanceProperties 0x0 
       list[1] 0x5dcc (struct protocol_t *) 
        isa 0x0 
       name 0x49ce UICollectionViewDataSource 
      protocols 0x53d8 
      instanceMethods 0x53e4 (struct method_list_t *) 
       entsize 12 
       count 2 
        name 0x394e collectionView:numberOfItemsInSection: 
       types 0x455d [email protected]:[email protected] 
        imp 0x0 
        name 0x3975 collectionView:cellForItemAtIndexPath: 
       types 0x4589 @[email protected]:[email protected]@12 
        imp 0x0 
      classMethods 0x0 (struct method_list_t *) 
     optionalInstanceMethods 0x5404 
     optionalClassMethods 0x0 
      instanceProperties 0x0 
        ivars 0x0 
      weakIvarLayout 0x0 
      baseProperties 0x0 
+0

我仍然有興趣爲與協議的情況雖然 - NS_CLASS_AVAILABLE似乎並不適用於那裏。 – Brynjar