Obj-C的已有類中,添加關(guān)聯(lián)對象存放自定義數(shù)據(jù)

全文引自
《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é)果。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容