Runtime的關(guān)聯(lián)

很多開源庫都使用了關(guān)聯(lián),我們可以不用修改類的定義而為其對象增加存儲空間。這在我們無法訪問到類的源碼的時候或者是考慮到二進制兼容性的時候是非常有用。
關(guān)聯(lián)是基于關(guān)鍵字的,因此,我們可以為任何對象增加任意多的關(guān)聯(lián),每個都使用不同的關(guān)鍵字即可。關(guān)聯(lián)是可以保證被關(guān)聯(lián)的對象在關(guān)聯(lián)對象的整個生命周期都是可用的(在垃圾自動回收環(huán)境下也不會導(dǎo)致資源不可回收)。

在類的定義之外為類增加額外的存儲空間

  • objc_setAssociatedObject
/** 
 * 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);

objc_setAssociatedObject把一個對象與另外一個對象進行關(guān)聯(lián)。該函數(shù)需要四個參數(shù):源對象,關(guān)鍵字,關(guān)聯(lián)的對象和一個關(guān)聯(lián)策略

關(guān)聯(lián)策略
/* Associative References */

/**
 * Policies related to associative references.
 * These are options to objc_setAssociatedObject()
 */
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
    //指定一個弱引用相關(guān)聯(lián)的對象
    OBJC_ASSOCIATION_ASSIGN = 0,           /**< Specifies a weak reference to the associated object. */
    //強引用關(guān)聯(lián)對象,非原子操作
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< Specifies a strong reference to the associated object. 
                                            *   The association is not made atomically. */
    //    復(fù)制關(guān)聯(lián)對象,非原子操作
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,   /**< Specifies that the associated object is copied. 
                                            *   The association is not made atomically. */
    //  強引用關(guān)聯(lián)對象,原子操作
    OBJC_ASSOCIATION_RETAIN = 01401,       /**< Specifies a strong reference to the associated object.
                                            *   The association is made atomically. */
    //    復(fù)制關(guān)聯(lián)對象,非原子操作
    OBJC_ASSOCIATION_COPY = 01403          /**< Specifies that the associated object is copied.
                                            *   The association is made atomically. */
};

OBJC_ASSOCIATION_ASSIGN 等價于 @property(assign)。
OBJC_ASSOCIATION_RETAIN_NONATOMIC等價于 @property(strong, nonatomic)。
OBJC_ASSOCIATION_COPY_NONATOMIC等價于@property(copy, nonatomic)。
OBJC_ASSOCIATION_RETAIN等價于@property(strong,atomic)。
OBJC_ASSOCIATION_COPY等價于@property(copy, atomic)。
/** 
//獲取關(guān)聯(lián)的對象
 * 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);
//斷開關(guān)聯(lián)
//或者直接使用objc_setAssociatedObject函數(shù),傳入nil值即可
/** 
 * 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
 */
OBJC_EXPORT void objc_removeAssociatedObjects(id object)
    OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);
* 例子
//給一個可變數(shù)組添加一個關(guān)聯(lián)
    static char overviewKey;
    NSMutableArray * marrDemo =[[NSMutableArray alloc] initWithObjects:@"1", @"2", @"3", nil];
    NSString * overview = [[NSString alloc] initWithFormat:@"%@",@"First three numbers"];
    objc_setAssociatedObject(marrDemo, &overviewKey, overview, OBJC_ASSOCIATION_RETAIN);
    
//獲取相關(guān)聯(lián)的對象
    NSString * associatedObject = (NSString *)objc_getAssociatedObject(marrDemo, &overviewKey);

//斷開關(guān)聯(lián)
//斷開關(guān)聯(lián)是使用objc_setAssociatedObject函數(shù),傳入nil值即可
    objc_setAssociatedObject(marrDemo, &overviewKey, nil, OBJC_ASSOCIATION_RETAIN);

分類,是不能添加屬性的,調(diào)用會崩潰的。
查了下文檔發(fā)現(xiàn),OC的分類允許給分類添加屬性,但不會自動生成getter、setter方法。有沒有解決方案呢?有,通過運行時建立關(guān)聯(lián)引用。

#import <UIKit/UIKit.h>

@interface UIViewController (ICEDemo)

@property (nonatomic, copy) NSString *str;

@end

#import "UIViewController+ICEDemo.h"
#import <objc/runtime.h>

static void *strKey = &strKey;

@implementation UIViewController (ICEDemo)

- (void)setStr:(NSString *)str {
    objc_setAssociatedObject(self, & strKey, str, OBJC_ASSOCIATION_COPY);
}

-(NSString *)str
{
    return objc_getAssociatedObject(self, &strKey);
}
@end
最后編輯于
?著作權(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)容