Associated Objects

簡介

Associated Objects (對象關(guān)聯(lián))支持以鍵值對的形式動態(tài)地向?qū)ο筇砑?,刪除,獲取關(guān)聯(lián)值。

使用場景

按照 Mattt Thompson 大神的文章 Associated Objects 中的說法,Associated Objects 主要有以下三個使用場景:

1.添加私有屬性用于更好地去實現(xiàn)細(xì)節(jié)
2.添加公有屬性增強Category的功能
3.為KVO創(chuàng)建一個關(guān)聯(lián)的觀察者

這里引用文章中的示例代碼,看不懂也沒關(guān)系后面我會再細(xì)說:

//NSObject+AssociatedObject.h
@interface NSObject (AssociatedObject) 
@property (nonatomic, strong) id associatedObject; 
@end 
//NSObject+AssociatedObject.m
#import "NSObject+AssociatedObject.h"
#import <objc/runtime.h>
@implementation NSObject (AssociatedObject) 
@dynamic associatedObject; 
 
- (void)setAssociatedObject:(id)object { 
     objc_setAssociatedObject(self, @selector(associatedObject), object, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
} 
 
- (id)associatedObject { 
    return objc_getAssociatedObject(self, @selector(associatedObject)); 
} 

這下原來無法添加實例變量的Category終于揚眉吐氣了。

使用方法

先來了解下<objc/runtime.h>中對應(yīng)的三個方法

// 設(shè)置關(guān)聯(lián)對象,value傳入nil來清除關(guān)聯(lián)對象
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
// 獲取關(guān)聯(lián)對象
id objc_getAssociatedObject(id object, const void *key);
// 清空所有關(guān)聯(lián)的對象(包括其他Client添加的),所以不應(yīng)該直接調(diào)用該方法
void objc_removeAssociatedObjects(id object);

key的選擇

需要注意的是,方法中用到的key通常來說該屬性應(yīng)該是常量、唯一的、在適用范圍內(nèi)用getter和setter訪問到的,有三種推薦使用的方式:

//1.使用char
static char kAssociatedObjectKey;
objc_getAssociatedObject(self, &kAssociatedObjectKey);
//2.使用指針
static void *kAssociatedObjectKey = &kAssociatedObjectKey;
objc_getAssociatedObject(self, kAssociatedObjectKey);
//3.使用selector
objc_getAssociatedObject(self, _cmd);
objc_setAssociatedObject(self, @selector(xxx),xxx,OBJC_ASSOCIATION_RETAIN_NONATOMIC);

關(guān)聯(lián)特性的選擇

另外一個需要注意的是objc_AssociationPolicy的類型特性:

行為 @property
OBJC_ASSOCIATION_ASSIGN @property (assign)、@property (unsafe_unretained)
OBJC_ASSOCIATION_RETAIN_NONATOMIC @property (nonatomic, strong)
OBJC_ASSOCIATION_COPY_NONATOMIC @property (nonatomic, copy)
OBJC_ASSOCIATION_RETAIN @property (atomic, strong)
OBJC_ASSOCIATION_COPY @property (atomic, copy)

實際應(yīng)用

大家對UIGestureRecognizer的用法應(yīng)該是再熟悉不過了

UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(invoke:)];
[tap addTarget:self action:@selector(invokeXX:)];
[self.view addGestureRecognizer:tap];

接著我拿ibireme大神 YYCategories 中的一段代碼來演示UIGestureRecognizer的文藝用法:

UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc]initWithActionBlock:^(id  _Nonnull sender) {
      //do something...
}];
[tap addActionBlock:^(id  _Nonnull sender) {
       //do something...
}];
[self.view addGestureRecognizer:tap];

UITapGestureRecognizer可以直接使用block來操作了。雖然只是使用風(fēng)格上的問題,但對于命名糾結(jié)癥的人來說是一大福音。

接下來,我們再探究下UIGestureRecognizer+YYAdd里的寶藏

//UIGestureRecognizer+YYAdd.h
NS_ASSUME_NONNULL_BEGIN //在該范圍內(nèi)傳入nil會給予警告
...
//初始化一個帶block的 gesture-recognizer 對象
- (instancetype)initWithActionBlock:(void (^)(id sender))block;
//給gesture-recognizer對象追加一個block
- (void)addActionBlock:(void (^)(id sender))block;
//刪除所有block
- (void)removeAllActionBlocks;
...
NS_ASSUME_NONNULL_END
//UIGestureRecognizer+YYAdd.m
static const int block_key; //< key值
...
- (instancetype)initWithActionBlock:(void (^)(id sender))block {
    self = [self init];
    [self addActionBlock:block];
    return self;
}

- (void)addActionBlock:(void (^)(id sender))block {
    _YYUIGestureRecognizerBlockTarget *target = [[_YYUIGestureRecognizerBlockTarget alloc] initWithBlock:block]; //< 初始化一個對象用于存儲block
    [self addTarget:target action:@selector(invoke:)];
    NSMutableArray *targets = [self _yy_allUIGestureRecognizerBlockTargets];
    [targets addObject:target]; //< 將持有block的對象放入數(shù)組中,方便管理
}

- (void)removeAllActionBlocks{ //< 清除所有綁定的target-action和block數(shù)組
    NSMutableArray *targets = [self _yy_allUIGestureRecognizerBlockTargets];
    [targets enumerateObjectsUsingBlock:^(id target, NSUInteger idx, BOOL *stop) {
        [self removeTarget:target action:@selector(invoke:)];
    }];
    [targets removeAllObjects];
}

- (NSMutableArray *)_yy_allUIGestureRecognizerBlockTargets {
    NSMutableArray *targets = objc_getAssociatedObject(self, &block_key); //< 從關(guān)聯(lián)對象中取得持有block對象的數(shù)組
    if (!targets) { //< 沒有的話就初始化一個并通過關(guān)聯(lián)對象動態(tài)添加
        targets = [NSMutableArray array];
        objc_setAssociatedObject(self, &block_key, targets, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return targets;
}

參考鏈接

http://nshipster.com/associated-objects/
http://blog.leichunfeng.com/blog/2015/06/26/objective-c-associated-objects-implementation-principle/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,703評論 2 380

推薦閱讀更多精彩內(nèi)容