iOS runtime實(shí)戰(zhàn)應(yīng)用:關(guān)聯(lián)對(duì)象

前言

在開(kāi)始之前建議先閱讀iOS runtime的基礎(chǔ)理解篇:iOS內(nèi)功篇:runtime

有筒子在面試的時(shí)候,遇到這樣一個(gè)問(wèn)題:“如何給NSArray添加一個(gè)屬性(不能使用繼承)”,筒子立馬蒙逼了抑诸,不能用繼承佩脊,難道用分類(lèi)亚再?但是分類(lèi)貌似只能添加方法不能添加屬性啊亲茅,筒子百思不得其解颁股,直到后來(lái)接觸到了runtime才恍然大悟盹廷。

什么是關(guān)聯(lián)對(duì)象

關(guān)聯(lián)對(duì)象是指某個(gè)OC對(duì)象通過(guò)一個(gè)唯一的key連接到一個(gè)類(lèi)的實(shí)例上征绸。
舉個(gè)例子:xiaoming是Person類(lèi)的一個(gè)實(shí)例,他的dog(一個(gè)OC對(duì)象)通過(guò)一根繩子(key)被他牽著散步俄占,這可以說(shuō)xiaoming和dog是關(guān)聯(lián)起來(lái)的管怠,當(dāng)然xiaoming可以牽著多個(gè)dog。

怎樣關(guān)聯(lián)對(duì)象

runtime提供給我們的方法:

//關(guān)聯(lián)對(duì)象
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
//獲取關(guān)聯(lián)的對(duì)象
id objc_getAssociatedObject(id object, const void *key)
//移除關(guān)聯(lián)的對(duì)象
void objc_removeAssociatedObjects(id object)

變量說(shuō)明:

id object:被關(guān)聯(lián)的對(duì)象(如xiaoming)
const void *key:關(guān)聯(lián)的key缸榄,要求唯一
id value:關(guān)聯(lián)的對(duì)象(如dog)
objc_AssociationPolicy policy:內(nèi)存管理的策略

objc_AssociationPolicy policy的enum值有:

OBJC_ASSOCIATION_ASSIGN = 0,          
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, 
OBJC_ASSOCIATION_COPY_NONATOMIC = 3,  
OBJC_ASSOCIATION_RETAIN = 01401,       
OBJC_ASSOCIATION_COPY = 01403   

當(dāng)對(duì)象被釋放時(shí)渤弛,會(huì)根據(jù)這個(gè)策略來(lái)決定是否釋放關(guān)聯(lián)的對(duì)象,當(dāng)策略是RETAIN/COPY時(shí)甚带,會(huì)釋放(release)關(guān)聯(lián)的對(duì)象她肯,當(dāng)是ASSIGN,將不會(huì)釋放鹰贵。
值得注意的是晴氨,我們不需要主動(dòng)調(diào)用removeAssociated來(lái)接觸關(guān)聯(lián)的對(duì)象,如果需要解除指定的對(duì)象碉输,可以使用setAssociatedObject置nil來(lái)實(shí)現(xiàn)籽前。

關(guān)聯(lián)對(duì)象的應(yīng)用

1、添加公共屬性

這是最常用的一個(gè)模式,通常我們會(huì)在類(lèi)聲明里面添加屬性聚假,但是出于某些需求(如前言描述的情況)块蚌,我們需要在分類(lèi)里添加一個(gè)或多個(gè)屬性的話,編譯器就會(huì)報(bào)錯(cuò)膘格,這個(gè)問(wèn)題的解決方案就是使用runtime的關(guān)聯(lián)對(duì)象峭范。
應(yīng)用舉例:
我們需要自定義一個(gè)tabbar,并暴露公共的屬性和方法瘪贱。(讀者們可以思考下使用繼承和分類(lèi)實(shí)現(xiàn)的優(yōu)點(diǎn)和不足之處)

@interface UITabBarController (Custom)

@property (nonatomic, strong) SUCustomTabbar * customTabbar;

@end
#import "UITabBarController+Custom.h"
#import <objc/runtime.h>

@implementation UITabBarController (Custom)

- (void)setCustomTabbar:(UIView *)customTabbar {
    //這里使用方法的指針地址作為唯一的key
    objc_setAssociatedObject(self, @selector(customTabbar), customTabbar, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (UIView *)customTabbar {
    return objc_getAssociatedObject(self, @selector(customTabbar));
}

//其他方法...

@end

這樣纱控,我們就可以像原生的tabbar一樣使用自定義的tabbar:

[self.tabBarController.customTabbar doSomgthig];

2、添加私有成員變量

有時(shí)候菜秦,需要在分類(lèi)中添加不想暴露在公共聲明的成員變量甜害。
應(yīng)用舉例:給按鈕添加點(diǎn)擊時(shí)間的回調(diào)

@interface UIButton (Callback)

- (instancetype)initWithFrame:(CGRect)frame callback:(void (^)(UIButton *))callbackBlock;

@end
@interface UIButton ()

@property (nonatomic, copy) void (^callbackBlock)(UIButton * button);

@end

@implementation UIButton (Callback)

- (void (^)(UIButton *))callbackBlock {
    return objc_getAssociatedObject(self, @selector(callbackBlock));
}

- (void)setCallbackBlock:(void (^)(UIButton *))callbackBlock {
    objc_setAssociatedObject(self, @selector(callbackBlock), callbackBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (instancetype)initWithFrame:(CGRect)frame callback:(void (^)(UIButton *))callbackBlock {
    
    if (self = [super initWithFrame:frame]) {
        self.callbackBlock = callbackBlock;
        [self addTarget:self action:@selector(didClickAction:) forControlEvents:UIControlEventTouchUpInside];
    }
    return self;
}

- (void)didClickAction:(UIButton *)button {
    self.callbackBlock(button);
}

@end

讀者思考:以上代碼是否會(huì)存在內(nèi)存管理的問(wèn)題

3、關(guān)聯(lián)KVO觀察者
有時(shí)候我們?cè)诜诸?lèi)中使用KVO球昨,推薦使用關(guān)聯(lián)的對(duì)象作為觀察者尔店,盡量避免對(duì)象觀察自身。
此應(yīng)用模式不再舉例主慰,有興趣的讀者可以自行深入研究嚣州,或者將代碼貼到評(píng)論處。

思考

1共螺、關(guān)聯(lián)對(duì)象更多的應(yīng)用模式该肴?
2、關(guān)聯(lián)對(duì)象是否是解決問(wèn)題的首選藐不?
3匀哄、關(guān)聯(lián)對(duì)象的副作用?

歡迎大家交流探討雏蛮。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末涎嚼,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子底扳,更是在濱河造成了極大的恐慌铸抑,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件衷模,死亡現(xiàn)場(chǎng)離奇詭異鹊汛,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)阱冶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)刁憋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人木蹬,你說(shuō)我怎么就攤上這事至耻。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵尘颓,是天一觀的道長(zhǎng)走触。 經(jīng)常有香客問(wèn)我,道長(zhǎng)疤苹,這世上最難降的妖魔是什么互广? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮卧土,結(jié)果婚禮上惫皱,老公的妹妹穿的比我還像新娘。我一直安慰自己尤莺,他們只是感情好旅敷,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著颤霎,像睡著了一般媳谁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上友酱,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天韩脑,我揣著相機(jī)與錄音,去河邊找鬼粹污。 笑死,一個(gè)胖子當(dāng)著我的面吹牛首量,可吹牛的內(nèi)容都是我干的壮吩。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼加缘,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼鸭叙!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起拣宏,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤沈贝,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后勋乾,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體宋下,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年辑莫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了学歧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡各吨,死狀恐怖枝笨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤横浑,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布剔桨,位于F島的核電站,受9級(jí)特大地震影響徙融,放射性物質(zhì)發(fā)生泄漏洒缀。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一张咳、第九天 我趴在偏房一處隱蔽的房頂上張望帝洪。 院中可真熱鬧,春花似錦脚猾、人聲如沸葱峡。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)砰奕。三九已至,卻和暖如春提鸟,著一層夾襖步出監(jiān)牢的瞬間军援,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工称勋, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留胸哥,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓赡鲜,卻偏偏與公主長(zhǎng)得像空厌,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子银酬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

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

  • 問(wèn)題:“如何給OC對(duì)象(如 NSArray嘲更、UIViewController等)添加一個(gè)屬性,且不使用繼承的情況下...
    O2Space_Xiu閱讀 800評(píng)論 0 0
  • 對(duì)于從事 iOS 開(kāi)發(fā)人員來(lái)說(shuō)揩瞪,所有的人都會(huì)答出【runtime 是運(yùn)行時(shí)】什么情況下用runtime?大部分人能...
    夢(mèng)夜繁星閱讀 3,697評(píng)論 7 64
  • 什么是關(guān)聯(lián)對(duì)象 關(guān)聯(lián)對(duì)象是指某個(gè)OC對(duì)象通過(guò)一個(gè)唯一的key連接到一個(gè)類(lèi)的實(shí)例上赋朦。 舉個(gè)例子:xiaoming是P...
    飄金閱讀 1,008評(píng)論 0 2
  • 周晨(大發(fā)化纖有限公司) 276期,感謝1組成員 【日精進(jìn)打卡第33天】 【知~學(xué)習(xí)】 《六項(xiàng)精進(jìn)》讀0遍 共70...
    周晨i閱讀 132評(píng)論 0 0
  • 有一天李破,爸爸坐在路邊休息宠哄,懷里抱著睡著了的孫女曙光,頭上的大草帽遮住了爺孫倆的頭臉喷屋。有個(gè)人走過(guò)來(lái)琳拨,好奇的問(wèn)到,“大...
    Bernardxiao閱讀 157評(píng)論 0 2