全文引自
《Effective Objective-C 2.0 編寫高質(zhì)量iOS與OS X代碼發(fā)的52個(gè)有效方法》劲妙,旨在為大家提供一點(diǎn)思路掖桦。Github 筆記
涉及到的方法
objc_setAssociatedObject
objc_getAssociatedObject
有時(shí)需要在對(duì)象中存儲(chǔ)相關(guān)信息限府,這時(shí)我們通常會(huì)從對(duì)象所屬的類中繼承一個(gè)子類夺颤,然后改用這個(gè)子類對(duì)象。然而胁勺,并非所有情況都能這么做世澜,有時(shí)候類的實(shí)例可能是由某種機(jī)制所創(chuàng)建的,而開發(fā)者無法令這種機(jī)制創(chuàng)建出自己所寫的子類實(shí)例署穗。Objective-C中有一項(xiàng)強(qiáng)大的特性可以解決此問題寥裂,這就是『關(guān)聯(lián)對(duì)象 Associated Object』。
可以給某對(duì)象關(guān)聯(lián)許多其他對(duì)象案疲,這些對(duì)象通過『鍵』來區(qū)分封恰。存儲(chǔ)對(duì)象值的時(shí)候,可以指明『存儲(chǔ)策略 storage policy』褐啡,用以維護(hù)相應(yīng)的"內(nèi)存管理語義"诺舔。存儲(chǔ)策略由名為objc-AssociationPolicy的枚舉所定定義,包括下面的值备畦,同事累出了與之等效的@property屬性:假如關(guān)聯(lián)對(duì)象成為了屬性低飒,那么它就會(huì)具備對(duì)應(yīng)的語義。
關(guān)聯(lián)類型 | 等效的屬性@property |
---|---|
OBJC_ASSOCIATION_COPY | copy |
OBJC_ASSOCIATION_RETAIN | retain |
OBJC_ASSOCIATION_ASSIGN | assign |
OBJC_ASSOCIATION_RETAIN_NONATOMIC | nonatomic, reatin |
OBJC_ASSOCIATION_COPY_NONATOMIC | nonatomic,copy |
下列方法可以管理關(guān)聯(lián)對(duì)象:
// 此方法以給定的鍵和策略為某對(duì)象設(shè)置關(guān)聯(lián)對(duì)象
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
// 此方法根據(jù)給定的鍵從某對(duì)象中獲取相應(yīng)的關(guān)聯(lián)對(duì)象值
id objc_getAssociatedObject(id object, const void *key)
// 此方法移除所指定對(duì)象的全部關(guān)聯(lián)對(duì)象
void objc_removeAssociatedObjects(id object)
舉例說明
______iOS開發(fā)中懂盐,之前經(jīng)常用到UIAlertView類『現(xiàn)在已經(jīng)過期』褥赊,該類提供了一種標(biāo)準(zhǔn)視圖,可向用戶展示警告信息莉恼。當(dāng)用戶按下按鈕關(guān)閉該視圖時(shí)崭倘,需要用委托協(xié)議(delegate protocol)來處理動(dòng)作,但是类垫,要想設(shè)置好這個(gè)委托機(jī)制司光,就得把創(chuàng)建警告視圖和處理按鈕動(dòng)作的代碼分開。由于代碼分做兩塊悉患,所以讀起來不方便残家。比如說,我們之前使用UIAlertView時(shí)售躁,一般會(huì)這么寫:
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"關(guān)聯(lián)對(duì)象" message:@"添加一個(gè)Block" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"好的", nil];
[alertView show];
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex == 0) {
[self cancelDeal];
}else{
[self doDeal];
}
}
____如果想在同一個(gè)類里坞淮,處理多個(gè)警告信息視圖茴晋,那么代碼就會(huì)變得更為復(fù)雜,我們必須在delegate方法中檢查傳入的alertView參數(shù)回窘,并根據(jù)此選用相應(yīng)的邏輯诺擅。要是能在創(chuàng)建警告視圖的時(shí)候直接把處理每個(gè)按鈕的邏輯都寫好,那就簡(jiǎn)單多了啡直。
____這可以通過關(guān)聯(lián)對(duì)象來做烁涌,創(chuàng)建完警告視圖之后,設(shè)定一個(gè)與之關(guān)聯(lián)的"塊 Block"酒觅,等到執(zhí)行delegate方法時(shí)再將其讀出來撮执。此方案的代碼實(shí)現(xiàn)如下:
#import <objc/runtime.h>
static void * kAlertBlockKey = @"AlertBlockKey";
- (void)showAlert{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"關(guān)聯(lián)對(duì)象" message:@"添加一個(gè)Block" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"好的", nil];
void (^touchAlertBlock)(NSInteger) = ^(NSInteger index) {
if (index == 0) {
[self cancelDeal];
}else{
[self doDeal];
}
};
objc_setAssociatedObject(alertView, kAlertBlockKey, touchAlertBlock, OBJC_ASSOCIATION_COPY);
[alertView show];
}
// UIAlertViewDelegate
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
void (^alertBlock)(NSInteger) = objc_getAssociatedObject(alertView, kAlertBlockKey);
if (alertBlock) {
alertBlock(buttonIndex);
}
}
Tip
上面的例子只是一個(gè)最簡(jiǎn)單的應(yīng)用,可以根據(jù)具體的需求實(shí)現(xiàn)自己想要的結(jié)果舷丹。