全文引自
《Effective Objective-C 2.0 編寫高質(zhì)量iOS與OS X代碼發(fā)的52個有效方法》,旨在為大家提供一點思路。Github 筆記
涉及到的方法
objc_setAssociatedObject
objc_getAssociatedObject
有時需要在對象中存儲相關(guān)信息,這時我們通常會從對象所屬的類中繼承一個子類,然后改用這個子類對象。然而,并非所有情況都能這么做,有時候類的實例可能是由某種機制所創(chuàng)建的,而開發(fā)者無法令這種機制創(chuàng)建出自己所寫的子類實例。Objective-C中有一項強大的特性可以解決此問題,這就是『關(guān)聯(lián)對象 Associated Object』。
可以給某對象關(guān)聯(lián)許多其他對象,這些對象通過『鍵』來區(qū)分。存儲對象值的時候,可以指明『存儲策略 storage policy』,用以維護相應(yīng)的"內(nèi)存管理語義"。存儲策略由名為objc-AssociationPolicy的枚舉所定定義,包括下面的值,同事累出了與之等效的@property屬性:假如關(guān)聯(lián)對象成為了屬性,那么它就會具備對應(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)對象:
// 此方法以給定的鍵和策略為某對象設(shè)置關(guān)聯(lián)對象
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
// 此方法根據(jù)給定的鍵從某對象中獲取相應(yīng)的關(guān)聯(lián)對象值
id objc_getAssociatedObject(id object, const void *key)
// 此方法移除所指定對象的全部關(guān)聯(lián)對象
void objc_removeAssociatedObjects(id object)
舉例說明
______iOS開發(fā)中,之前經(jīng)常用到UIAlertView類『現(xiàn)在已經(jīng)過期』,該類提供了一種標準視圖,可向用戶展示警告信息。當用戶按下按鈕關(guān)閉該視圖時,需要用委托協(xié)議(delegate protocol)來處理動作,但是,要想設(shè)置好這個委托機制,就得把創(chuàng)建警告視圖和處理按鈕動作的代碼分開。由于代碼分做兩塊,所以讀起來不方便。比如說,我們之前使用UIAlertView時,一般會這么寫:
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"關(guān)聯(lián)對象" message:@"添加一個Block" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"好的", nil];
[alertView show];
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex == 0) {
[self cancelDeal];
}else{
[self doDeal];
}
}
____如果想在同一個類里,處理多個警告信息視圖,那么代碼就會變得更為復(fù)雜,我們必須在delegate方法中檢查傳入的alertView參數(shù),并根據(jù)此選用相應(yīng)的邏輯。要是能在創(chuàng)建警告視圖的時候直接把處理每個按鈕的邏輯都寫好,那就簡單多了。
____這可以通過關(guān)聯(lián)對象來做,創(chuàng)建完警告視圖之后,設(shè)定一個與之關(guān)聯(lián)的"塊 Block",等到執(zhí)行delegate方法時再將其讀出來。此方案的代碼實現(xiàn)如下:
#import <objc/runtime.h>
static void * kAlertBlockKey = @"AlertBlockKey";
- (void)showAlert{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"關(guān)聯(lián)對象" message:@"添加一個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
上面的例子只是一個最簡單的應(yīng)用,可以根據(jù)具體的需求實現(xiàn)自己想要的結(jié)果。