原文地址: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í),該方法還是蠻有用的。