Objective-C Associated Objects

Objective-C開發(fā)者應該小心謹慎地遵循這個危險咒語的各種準則芽狗。一個很好的原因的就是:混亂的運行時代碼會改變運行在其架構之上的所有代碼檬寂。

當然,<objc/runtime.h>中的函數能實現(xiàn)許多強大的功能籍铁,而且又是其他很難做到的功能堡距。以我自己遇到的舉例:曾接手一個項目,繼承混亂媚送,要加新功能之碗,對每個頁面進行統(tǒng)計。能做到對現(xiàn)有代碼沒有侵入性的方法就是runtime季希,通過關聯(lián)系統(tǒng)方法褪那,自定義方法去實現(xiàn)真正的功能,僅僅需要一個UIViewController的category就可以做到式塌。

Associated Objects(關聯(lián)對象)

主要函數

在系統(tǒng)文件<objc/runtime.h>中很容易就找到主要相關的三個函數:

/** 
 * Sets an associated value for a given object using a given key and association policy.
 * 
 * @param object The source object for the association.
 * @param key The key for the association.
 * @param value The value to associate with the key key for object. Pass nil to clear an existing association.
 * @param policy The policy for the association. For possible values, see “Associative Object Behaviors.”
 * 
 * @see objc_setAssociatedObject
 * @see objc_removeAssociatedObjects
 */
OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
    OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);

/** 
 * Returns the value associated with a given object for a given key.
 * 
 * @param object The source object for the association.
 * @param key The key for the association.
 * 
 * @return The value associated with the key \e key for \e object.
 * 
 * @see objc_setAssociatedObject
 */
OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key)
    OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);

/** 
 * Removes all associations for a given object.
 * 
 * @param object An object that maintains associated objects.
 * 
 * @note The main purpose of this function is to make it easy to return an object 
 *  to a "pristine state”. You should not use this function for general removal of
 *  associations from objects, since it also removes associations that other clients
 *  may have added to the object. Typically you should use \c objc_setAssociatedObject 
 *  with a nil value to clear an association.
 * 
 * @see objc_setAssociatedObject
 * @see objc_getAssociatedObject
 */
OBJC_EXPORT void objc_removeAssociatedObjects(id object)
    OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);

函數的命名意思十分明顯

  • objc_setAssociatedObject 給對象添加關聯(lián)對象
  • objc_getAssociatedObject 獲取關聯(lián)對象
  • objc_removeAssociatedObjects 移除所有關聯(lián)對象(返回一個對象為"原始狀態(tài)")
    這里第三個函數注意下上面官方的注釋

The main purpose of this function is to make it easy to return an object to a "pristine state”. You should not use this function for general removal of associations from objects, since it also removes associations that other clients may have added to the object. Typically you should use \c objc_setAssociatedObject with a nil value to clear an association.

因為這個函數會移除所有的關聯(lián)對象博敬,很可能把別人添加的關聯(lián)對象也刪除。所以通常使用objc_setAssociatedObject函數傳入nil值根據key移除存在的某關聯(lián)對象峰尝。

函數參數

id object 被關聯(lián)對象
const void *key 唯一的key值
id value 關聯(lián)對象
objc_AssociationPolicy policy 對關聯(lián)對象的持有策略

其中key的值是void指針偏窝,可以用三種方式做唯一值。

  • 聲明static char SomeAssociatedKey; 使用&SomeAssociatedKey 作為唯一值武学。
  • 聲明static void *SomeAssociatedKey; 使用SomeAssociatedKey 作為唯一值祭往。
  • 利用selector函數地址作為唯一值。

屬性可以根據定義在枚舉類型objc_AssociationPolicy policy上的行為被關聯(lián)在對象上:

OBJC_ASSOCIATION_ASSIGN @property (assign) 或 @property (unsafe_unretained) 指定一個關聯(lián)對象的弱引用火窒。
OBJC_ASSOCIATION_RETAIN_NONATOMIC @property (nonatomic, strong) 指定一個關聯(lián)對象的強引用硼补,不能被原子化使用。
OBJC_ASSOCIATION_COPY_NONATOMIC @property (nonatomic, copy) 指定一個關聯(lián)對象的copy引用熏矿,不能被原子化使用已骇。
OBJC_ASSOCIATION_RETAIN @property (atomic, strong) 指定一個關聯(lián)對象的強引用离钝,能被原子化使用。
OBJC_ASSOCIATION_COPY @property (atomic, copy) 指定一個關聯(lián)對象的copy引用褪储,能被原子化使用卵渴。

簡單例子

以UIButton為例為UIButton的category添加block屬性

#import <UIKit/UIKit.h>

typedef void(^touchBlock)(void);

@interface UIButton (Block)

- (void)handleTouchUpInside:(touchBlock)block;

@end

#import "UIButton+Block.h"
#import <objc/runtime.h>

@implementation UIButton (Block)

- (void)handleTouchUpInside:(touchBlock)block {
    objc_setAssociatedObject(self, @selector(handleTouchUpInside:), block, OBJC_ASSOCIATION_COPY_NONATOMIC);
    [self addTarget:self action:@selector(touchUpInsideBlock) forControlEvents:UIControlEventTouchUpInside];
}

- (void)touchUpInsideBlock {
    touchBlock block = objc_getAssociatedObject(self, @selector(handleTouchUpInside:));
    if (block) {
        block();
    }
}
@end

這樣為UIButton添加block屬性,在使用的時候代碼會比較集中:

UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
button.backgroundColor = [UIColor redColor];
[button handleTouchUpInside:^{
        NSLog(@"觸發(fā)touchUpInside事件");
}];
[self.view addSubview:button];

比起其他解決問題的方法鲤竹,關聯(lián)對象應該被視為最后的選擇(事實上category也不應該作為首選方法)浪读。
和其他精巧的trick、hack辛藻、workaround一樣碘橘,一般人都會在剛學習完之后樂于尋找場景去使用一下。盡你所能去理解和欣賞它在正確使用時它所發(fā)揮的作用揩尸,同時當你選擇這個解決辦法時蛹屿,也要避免當被輕蔑地問起“這是個什么玩意屁奏?”時的尷尬岩榆。


相關參考: Associated Objects

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市坟瓢,隨后出現(xiàn)的幾起案子勇边,更是在濱河造成了極大的恐慌,老刑警劉巖折联,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件粒褒,死亡現(xiàn)場離奇詭異,居然都是意外死亡诚镰,警方通過查閱死者的電腦和手機奕坟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來清笨,“玉大人月杉,你說我怎么就攤上這事】侔” “怎么了苛萎?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長检号。 經常有香客問我腌歉,道長,這世上最難降的妖魔是什么齐苛? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任翘盖,我火速辦了婚禮,結果婚禮上凹蜂,老公的妹妹穿的比我還像新娘最仑。我一直安慰自己藐俺,他們只是感情好,可當我...
    茶點故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布泥彤。 她就那樣靜靜地躺著欲芹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪吟吝。 梳的紋絲不亂的頭發(fā)上菱父,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天,我揣著相機與錄音剑逃,去河邊找鬼浙宜。 笑死,一個胖子當著我的面吹牛蛹磺,可吹牛的內容都是我干的粟瞬。 我是一名探鬼主播,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼萤捆,長吁一口氣:“原來是場噩夢啊……” “哼裙品!你這毒婦竟也來了?” 一聲冷哼從身側響起俗或,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤市怎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后辛慰,有當地人在樹林里發(fā)現(xiàn)了一具尸體区匠,經...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年帅腌,在試婚紗的時候發(fā)現(xiàn)自己被綠了驰弄。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡速客,死狀恐怖戚篙,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情挽封,我是刑警寧澤已球,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站辅愿,受9級特大地震影響智亮,放射性物質發(fā)生泄漏。R本人自食惡果不足惜点待,卻給世界環(huán)境...
    茶點故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一阔蛉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧癞埠,春花似錦状原、人聲如沸聋呢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽削锰。三九已至,卻和暖如春毕莱,著一層夾襖步出監(jiān)牢的瞬間器贩,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工朋截, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蛹稍,地道東北人。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓部服,卻偏偏與公主長得像唆姐,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子廓八,可洞房花燭夜當晚...
    茶點故事閱讀 44,678評論 2 354

推薦閱讀更多精彩內容