說說 Objc Runtime 中的 Associated Objects

今天我們聊聊 Associated Objects, 它也是 Objc Runtime 中提供的特性, 在我們日常開發中的應用上還是挺多的。 如果你之前沒有接觸過這個概念,相信這篇內容值得一看。

Associated Objects

Associated Objects 的一個最常見的應用就是給已有的類添加屬性。 如果你使用 Objective-C 語言的話,可以用 Category 給某個已經存在的類添加方法。 但是 Category 卻不能給這個類添加實例變量。 比如我們想給 UIView 實現一個字符串類型的 tag(UIView 默認的 tag 實現只能添加 int 類型的值),按照現有的語法就沒辦法存儲這個 tag 的實例變量。

你可以這樣實現 UIView 的 Category:

@interface UIView (StringTag)

@property (nonatomic, strong) NSString *stringTag;

@end

這時,我們聲明一個 UIView 並給他的 stringTag 屬性賦值:

UIView *view = [[UIView alloc] init];
view.stringTag = @"map";

語法和編譯都正常,但運行的時候,控制檯中就會提示這樣的信息:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIView setStringTag:]: unrecognized selector sent to instance 0x7fda52d9a2c0'

程序崩潰了。 雖然我們聲明瞭屬性, 但 @property 實際上還是會調用 [UIView setStringTag:] 方法設置實例變量, 但 Category 中是不支持實例變量的,所以就會導致程序在運行時崩潰。 這個例子也能幫助大家加深對 Objc Runtime 的瞭解。

那麼,我們想在 Category 中也能添加實例變量的話該怎麼辦呢? 這時就可以使用 Associated Object 機制, 在運行時爲我們的 UIView 關聯屬性,將剛剛定義的 Category 實現稍加修改即可達成目標:

@implementation UIView (StringTag)

- (void)setStringTag:(NSString *)stringTag {
    
    objc_setAssociatedObject(self, @selector(stringTag), stringTag, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    
}

- (NSString *)stringTag {
    
    return objc_getAssociatedObject(self, @selector(stringTag));
    
}

@end

這樣,我們在 Category 中使用 Assocaited Object 在運行時完成了實例變量的設置。 這時候再次運行程序, 剛纔對 UIView 相關操作的代碼就能夠順利的執行啦。

objc_setAssociatedObject 方法接受 4 個參數, 第一個參數是要將關聯值設置到的實例, 第二個是這個關聯值的標識 key, 第三個是這個關聯值自身, 第四個是這個關聯屬性的處理方式。

我們注意到它的第二個參數,這裏用了 @selector(stringTag) 這種形式。 雖然這個參數代表的是一個 key, 但它的類型不是 NSString, 而是一個 void * 的指針,這就意味着我們可以將任何符合這個類型條件的值設置給它。 @selector(stringTag) 就符合這樣的類型,所以我們不必再定義一個變量來表示這個關聯值的 key, 只需要將和他屬性名對應的 Selector 傳遞進來即可。

同樣的,objc_getAssociatedObject 用於獲取關聯屬性的名稱。 它接受兩個參數, 其中包括關聯值所在的對象,以及它的標識 key。

總結

這裏用最簡單的篇幅給大家介紹了 Associated Object 在我們平時開發中的應用,對 Category 屬性的這個應用很常見,比如著名的框架 AFNetworking 裏面就對很多 Category 中的屬性定義使用了 Associated Object。 大家有興趣可以參看它對 UIImage 的 Categoy 定義。 關於 Assoicated Object 更詳細的內容,這裏的篇幅肯定沒有介紹全面,大家還可以參看蘋果官方關於 Objective-C Runtime 的文檔深入瞭解。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章