原文地址:http://www.jkeabc.com/649648.html
附:關(guān)聯(lián)對象 AssociatedObject 完全解析http://www.reibang.com/p/79479a09a8c0
iOS 運(yùn)行時之 Associative(關(guān)聯(lián))
iOS 下有很多運(yùn)行時特性,這里介紹一下 Associative(關(guān)聯(lián)) 這個運(yùn)行時特性秘血,以及它一些使用場景被环。 Associative 意思為關(guān)聯(lián)奋隶,
iOS 下有很多運(yùn)行時特性研侣,這里介紹一下 Associative(關(guān)聯(lián))
這個運(yùn)行時特性矢劲,以及它一些使用場景蒲拉。 Associative
意思為關(guān)聯(lián),能夠?qū)蓚€對象建立一種關(guān)系忽冻。這種關(guān)系是一種 從屬
關(guān)系真朗,也就是說有一個 關(guān)聯(lián)者
和一個 被關(guān)聯(lián)者
。比如說我們可以將一個 NSString
對象關(guān)聯(lián)到一個 UIView
對象上僧诚。這里的 NSString
對象就是 被關(guān)聯(lián)者
, UIView
對象就是 關(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
*/
同時還提供以下枚舉類型的定義:
/**
* 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 為我們提供了將兩個對象建立關(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ù)可以通過該 KEY 值找到該 被關(guān)聯(lián)者
objc_AssociationPolicy policy
: 該參數(shù)作用用來表示 被關(guān)聯(lián)者
的引用策略慈省,也就是內(nèi)存如何進(jìn)行管理的臀防,可通過上述定義的枚舉類型來設(shè)置。
id objc_getAssociatedObject(id object, const void *key)
API 可以通過之前設(shè)置的 KEY 值边败,來獲取 被關(guān)聯(lián)者
對象袱衷,參數(shù)解析如下:
id object
: 關(guān)聯(lián)者
對象
const void *key
:要獲取的 被關(guān)聯(lián)者
的 KEY 值,一個 關(guān)聯(lián)者
可以被關(guān)聯(lián)多對象放闺,一個 關(guān)聯(lián)者
也可以是 被關(guān)聯(lián)這
祟昭,可以通過不同的 KEY 來獲取不同的 被關(guān)聯(lián)者
對象缕坎。
void objc_removeAssociatedObjects(id object)
該 API 可以移除一個 關(guān)聯(lián)者
對象所有的 被關(guān)聯(lián)者
怖侦。當(dāng)需要移除特定的對象時,我們可以使用 objc_setAssociatedObject
方法并指定 id value
參數(shù)對象為空即可谜叹。
以上就是關(guān)于 Associative(關(guān)聯(lián))
特性相關(guān)的 API 介紹了匾寝,下面介紹一下常用的使用場景。
Associative 特性的應(yīng)用
剪切板的信息復(fù)制
在一些時候我們希望用戶可以長按文案信息荷腊,彈出系統(tǒng)的復(fù)制菜單艳悔,提供文案信息的復(fù)制功能,比如長按 UITableViewCell
提供復(fù)制詳情的功能女仰,在 iOS 下我們可以使用 UIMenuController
類來顯示系統(tǒng)菜單猜年,同時為該 UITableViewCell
添加長按手勢,代碼如下:
// 添加長按手勢
UILongPressGestureRecognizer *longPressGR = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
[cell addGestureRecognizer:longPressGR];
// 手勢處理
- (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:
方法中乔外,但是在該方法中,并不能訪問到 cell.detailTextLabel
對象一罩,在該場景中杨幼,我們可以使用 Associative
特性將 UITableViewCell
對象關(guān)聯(lián)到 UIMenuController
對象中,再在 copy:
方法中獲取到被關(guān)聯(lián)對象,從而獲取到 UITableViewCell
對象差购,進(jìn)而訪問 cell.detailTextLabel.text
四瘫。添加代碼如下:
// 處理手勢時,添加如下代碼
objc_setAssociatedObject(menu, @"UITableViewCell", longPressGR.view, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
// 處理 copy 時欲逃,添加如下代碼找蜜,來獲取被關(guān)聯(lián)的 UITableViewCell 對象
objc_getAssociatedObject(menu, @"UITableViewCell");
pasteboard.string = cell.detailTextLabel.text;
上述場景中,并不一定非得用 Associative
特性來實(shí)現(xiàn)稳析,還有很多可行的方法锹杈,這里為大家提供一種方法,并且該方法還算是比較優(yōu)雅的迈着。
其他一些應(yīng)用場景
另一個常見的應(yīng)用場景就是竭望,為一個系統(tǒng)類或是一個第三方的類添加一個屬性時,可以結(jié)合 Category
為類添加一個屬性裕菠,當(dāng)然也可以使用繼承來達(dá)到目的咬清。在一些特殊場景下,比如想知道一個系統(tǒng)內(nèi)部對象或者第三方對象是何時被釋放時奴潘,我們可以為該對象關(guān)聯(lián)一個自定義的對象旧烧,并且使用 OBJC_ASSOCIATION_RETAIN_NONATOMIC
來指定內(nèi)存管理策略,當(dāng)關(guān)聯(lián)者被釋放是画髓,被關(guān)聯(lián)者也會跟著被釋放掘剪,這樣可以在我們自定義的對象中,知道感興趣的對象何時被釋放的奈虾。在調(diào)試一些內(nèi)存問題時夺谁,該方法還是蠻有用的。