關(guān)聯(lián)引用(Associative References)

關(guān)聯(lián)引用:能夠?qū)⒛硞€(gè)對象作為value通過唯一的key與另一個(gè)對象進(jìn)行關(guān)聯(lián),作為value的對象可以看作是另一對象的一部分。能夠讓開發(fā)者給使用category的類中添加自定義屬性。
關(guān)聯(lián)對象(associated object):在runtime函數(shù)中作為關(guān)聯(lián)值(associated value),例如將對象b作為關(guān)聯(lián)對象(或關(guān)聯(lián)值)與對象a以key值進(jìn)行關(guān)聯(lián)

NSObject a = [[NSObject alloc]init];
NSObject b = [[NSObject alloc]init];
objc_setAssociatedObject(a, key, b, OBJC_ASSOCIATION_ASSIGN); 

runtime與關(guān)聯(lián)引用有關(guān)的方法

  • 創(chuàng)建關(guān)聯(lián)引用

      /**
      * 通過給定的key和關(guān)聯(lián)策略,為給定對象創(chuàng)建一個(gè)關(guān)聯(lián)value   
      * @param object 進(jìn)行關(guān)聯(lián)操作的源對象The source object for the assciation.
      * @param key 關(guān)聯(lián)引用需要的key值.
      * @param value 與Key值關(guān)聯(lián)的value,value為nil,可清除已存在的關(guān)聯(lián)
      * @param policy關(guān)聯(lián)策略
      **/
      void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
    
  • 獲取關(guān)聯(lián)對象

      /**
      * 按照給定對象和給定key返回關(guān)聯(lián)的value
      * @param object 關(guān)聯(lián)操作的源對象
      * @param key 關(guān)聯(lián)操作的key.
      * @return 通過key與對象進(jìn)行關(guān)聯(lián)的value.
      */
      id objc_getAssociatedObject(id object, const void *key)
    
  • 移除關(guān)聯(lián)引用

      /**
       * 移除對象所有的關(guān)聯(lián)引用
       * @param object 具有關(guān)聯(lián)引用的對象.
       * @note 這個(gè)函數(shù)的目的是為了方便獲取給定對象的沒有任何關(guān)聯(lián)引用原始狀態(tài)。
       * 不應(yīng)該用這個(gè)函數(shù)移除某個(gè)value與對象的關(guān)聯(lián)引用,因?yàn)檫@樣也會(huì)移除這個(gè)對
       * 象與其它對象的關(guān)聯(lián)引用。通常,應(yīng)使用objc_setAssociatedObject,傳入
       * nil的value來清除對象與某個(gè)已存在的value的關(guān)聯(lián)引用
       */
       void objc_removeAssociatedObjects(id object)
    

關(guān)聯(lián)策略(objc_AssociationPolicy)

typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
    OBJC_ASSOCIATION_ASSIGN = 0,           /**< 指定關(guān)聯(lián)對象的弱引用 */
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< 指定關(guān)聯(lián)對象的非原子性的強(qiáng)引用*/
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,   /**< 指定關(guān)聯(lián)對象為copy類型并且非原子性*/
    OBJC_ASSOCIATION_RETAIN = 01401,       /**< 指定關(guān)聯(lián)對象為原子性強(qiáng)引用*/
    OBJC_ASSOCIATION_COPY = 01403          /**< 指定關(guān)聯(lián)對象為原子性的copy*/
};

關(guān)聯(lián)引用的使用方式

  1. 添加私有成員變量
  2. 給category添加公共屬性
  3. 為KVO創(chuàng)建關(guān)聯(lián)的觀察者對象:當(dāng)在category中使用KVO時(shí),推薦使用自定義的關(guān)聯(lián)對象作為觀察者,可以參考文章Objective-C Associated Objects

示例:在category中添加屬性

  1. .h文件

     @interface NSObject (Custom) {
     //    NSString *str0;        //使用category的類中不能添加成員變量
     }
     @property (nonatomic, strong) NSString *str1;
     @end
    
  2. .m文件

     #import "NSObject+Custom.h"
     #import <objc/runtime.h>
     @implementation NSObject (Custom)
     @dynamic str1;  //這里使用@dynamic告訴編譯器在編譯期間不要自動(dòng)創(chuàng)建屬性的存取方法,也可以不用寫(因?yàn)榭梢詫ν姆椒ㄟM(jìn)行override)
     //定義key值,一般為靜態(tài)char類型,最簡便的方式就是用SEL類型作為key值
     //static char key;
    
     - (void)setStr1:(NSString *)str1 {
     //    objc_setAssociatedObject(self, &key, str1, OBJC_ASSOCIATION_COPY_NONATOMIC);
     //用SEL代替static char的key
         objc_setAssociatedObject(self, @selector(str1), str1,   OBJC_ASSOCIATION_COPY);
     }
    
     - (NSString *)str1 {
     //    return objc_getAssociatedObject(self, &key);
     //用SEL類型代替static char的key
         return objc_getAssociatedObject(self, @selector(str1));
     }
     @end
    

使用注意

當(dāng)在category中定義了與class同名的成員時(shí),會(huì)category中的成員會(huì)覆蓋class中的成員,這是因?yàn)間etter方法會(huì)優(yōu)先尋找category中的屬性。

參考文章

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

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

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