iOS 運(yùn)行時(shí)之 Associative(關(guān)聯(lián))

原文地址:http://www.jkeabc.com/649648.html
附:關(guān)聯(lián)對(duì)象 AssociatedObject 完全解析http://www.itdecent.cn/p/79479a09a8c0

iOS 運(yùn)行時(shí)之 Associative(關(guān)聯(lián))
iOS 下有很多運(yùn)行時(shí)特性,這里介紹一下 Associative(關(guān)聯(lián)) 這個(gè)運(yùn)行時(shí)特性,以及它一些使用場(chǎng)景。 Associative 意思為關(guān)聯(lián),
iOS 下有很多運(yùn)行時(shí)特性,這里介紹一下 Associative(關(guān)聯(lián))

這個(gè)運(yùn)行時(shí)特性,以及它一些使用場(chǎng)景。 Associative

意思為關(guān)聯(lián),能夠?qū)蓚€(gè)對(duì)象建立一種關(guān)系。這種關(guān)系是一種 從屬

關(guān)系,也就是說(shuō)有一個(gè) 關(guān)聯(lián)者

和一個(gè) 被關(guān)聯(lián)者

。比如說(shuō)我們可以將一個(gè) NSString

對(duì)象關(guān)聯(lián)到一個(gè) UIView

對(duì)象上。這里的 NSString

對(duì)象就是 被關(guān)聯(lián)者

, UIView

對(duì)象就是 關(guān)聯(lián)者

。

在 objc/runtime.h

文件中,找到 Associative

相關(guān)的 API 定義,如下:

/** 
 * Sets an associated value for a given object using a given key and association policy.

 * 

 * @param object The source object for the association.

 * @param key The key for the association.

 * @param value The value to associate with the key key for object. Pass nil to clear an existing association.

 * @param policy The policy for the association. For possible values, see “Associative Object Behaviors.”

 * 

 * @see objc_setAssociatedObject

 * @see objc_removeAssociatedObjects

 */

OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)

    OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);

/** 

 * Returns the value associated with a given object for a given key.

 * 

 * @param object The source object for the association.

 * @param key The key for the association.

 * 

 * @return The value associated with the key /e key for /e object.

 * 

 * @see objc_setAssociatedObject

 */

OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key)

    OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);

/** 

 * Removes all associations for a given object.

 * 

 * @param object An object that maintains associated objects.

 * 

 * @note The main purpose of this function is to make it easy to return an object 

 *  to a "pristine state”. You should not use this function for general removal of

 *  associations from objects, since it also removes associations that other clients

 *  may have added to the object. Typically you should use /c objc_setAssociatedObject 

 *  with a nil value to clear an association.

 * 

 * @see objc_setAssociatedObject

 * @see objc_getAssociatedObject

 */

同時(shí)還提供以下枚舉類(lèi)型的定義:

/**
 * Policies related to associative references.

 * These are options to objc_setAssociatedObject()

 */

typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {

    OBJC_ASSOCIATION_ASSIGN = 0,           /**< Specifies a weak reference to the associated object. */

    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< Specifies a strong reference to the associated object. 

                                            *   The association is not made atomically. */

    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,   /**< Specifies that the associated object is copied. 

                                            *   The association is not made atomically. */

    OBJC_ASSOCIATION_RETAIN = 01401,       /**< Specifies a strong reference to the associated object.

                                            *   The association is made atomically. */

    OBJC_ASSOCIATION_COPY = 01403          /**< Specifies that the associated object is copied.

                                            *   The association is made atomically. */

};

API 解析
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)

API 為我們提供了將兩個(gè)對(duì)象建立關(guān)聯(lián)關(guān)系的能力,參數(shù)解析為:

id object

:指定 關(guān)聯(lián)者

id value

:指定 被關(guān)聯(lián)者

const void *key

: 被關(guān)聯(lián)者

的 KEY 值,方便后續(xù)可以通過(guò)該 KEY 值找到該 被關(guān)聯(lián)者

objc_AssociationPolicy policy

: 該參數(shù)作用用來(lái)表示 被關(guān)聯(lián)者

的引用策略,也就是內(nèi)存如何進(jìn)行管理的,可通過(guò)上述定義的枚舉類(lèi)型來(lái)設(shè)置。

id objc_getAssociatedObject(id object, const void *key)

API 可以通過(guò)之前設(shè)置的 KEY 值,來(lái)獲取 被關(guān)聯(lián)者

對(duì)象,參數(shù)解析如下:

id object

: 關(guān)聯(lián)者

對(duì)象

const void *key

:要獲取的 被關(guān)聯(lián)者

的 KEY 值,一個(gè) 關(guān)聯(lián)者

可以被關(guān)聯(lián)多對(duì)象,一個(gè) 關(guān)聯(lián)者

也可以是 被關(guān)聯(lián)這

,可以通過(guò)不同的 KEY 來(lái)獲取不同的 被關(guān)聯(lián)者

對(duì)象。

void objc_removeAssociatedObjects(id object)

該 API 可以移除一個(gè) 關(guān)聯(lián)者

對(duì)象所有的 被關(guān)聯(lián)者

。當(dāng)需要移除特定的對(duì)象時(shí),我們可以使用 objc_setAssociatedObject

方法并指定 id value

參數(shù)對(duì)象為空即可。

以上就是關(guān)于 Associative(關(guān)聯(lián))

特性相關(guān)的 API 介紹了,下面介紹一下常用的使用場(chǎng)景。

Associative 特性的應(yīng)用
剪切板的信息復(fù)制
在一些時(shí)候我們希望用戶可以長(zhǎng)按文案信息,彈出系統(tǒng)的復(fù)制菜單,提供文案信息的復(fù)制功能,比如長(zhǎng)按 UITableViewCell

提供復(fù)制詳情的功能,在 iOS 下我們可以使用 UIMenuController

類(lèi)來(lái)顯示系統(tǒng)菜單,同時(shí)為該 UITableViewCell

添加長(zhǎng)按手勢(shì),代碼如下:

// 添加長(zhǎng)按手勢(shì)
UILongPressGestureRecognizer *longPressGR = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];

[cell addGestureRecognizer:longPressGR];

// 手勢(shì)處理

- (void)handleLongPress:(UILongPressGestureRecognizer *) longPressGR {

    UIMenuController *menu = [UIMenuController sharedMenuController];

    [menu setTargetRect:longPressGR.view.frame inView:self.view];

    [menu setMenuVisible:YES animated:YES];

}

// UIMenuController 相關(guān)

- (BOOL)canBecomeFirstResponder {

    return YES;

}

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {

    if ( action == @selector(copy:) ) {

        return YES;

    }

    return NO;

}

- (void)copy:(UIMenuController *)menu {

    UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];

}

從上述代碼可以看到,復(fù)制信息的邏輯處理是在 copy:

方法中,但是在該方法中,并不能訪問(wèn)到 cell.detailTextLabel

對(duì)象,在該場(chǎng)景中,我們可以使用 Associative

特性將 UITableViewCell

對(duì)象關(guān)聯(lián)到 UIMenuController

對(duì)象中,再在 copy:

方法中獲取到被關(guān)聯(lián)對(duì)象,從而獲取到 UITableViewCell

對(duì)象,進(jìn)而訪問(wèn) cell.detailTextLabel.text

。添加代碼如下:

// 處理手勢(shì)時(shí),添加如下代碼
objc_setAssociatedObject(menu, @"UITableViewCell", longPressGR.view, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

// 處理 copy 時(shí),添加如下代碼,來(lái)獲取被關(guān)聯(lián)的 UITableViewCell 對(duì)象

objc_getAssociatedObject(menu, @"UITableViewCell");

pasteboard.string = cell.detailTextLabel.text;

上述場(chǎng)景中,并不一定非得用 Associative

特性來(lái)實(shí)現(xiàn),還有很多可行的方法,這里為大家提供一種方法,并且該方法還算是比較優(yōu)雅的。

其他一些應(yīng)用場(chǎng)景
另一個(gè)常見(jiàn)的應(yīng)用場(chǎng)景就是,為一個(gè)系統(tǒng)類(lèi)或是一個(gè)第三方的類(lèi)添加一個(gè)屬性時(shí),可以結(jié)合 Category

為類(lèi)添加一個(gè)屬性,當(dāng)然也可以使用繼承來(lái)達(dá)到目的。在一些特殊場(chǎng)景下,比如想知道一個(gè)系統(tǒng)內(nèi)部對(duì)象或者第三方對(duì)象是何時(shí)被釋放時(shí),我們可以為該對(duì)象關(guān)聯(lián)一個(gè)自定義的對(duì)象,并且使用 OBJC_ASSOCIATION_RETAIN_NONATOMIC

來(lái)指定內(nèi)存管理策略,當(dāng)關(guān)聯(lián)者被釋放是,被關(guān)聯(lián)者也會(huì)跟著被釋放,這樣可以在我們自定義的對(duì)象中,知道感興趣的對(duì)象何時(shí)被釋放的。在調(diào)試一些內(nèi)存問(wèn)題時(shí),該方法還是蠻有用的。

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

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

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