OC底層知識(五) :關(guān)聯(lián)對象

上一篇博客里面寫到如何實現(xiàn)給分類添加成員變量?,在這里咱們通過學(xué)習(xí)關(guān)聯(lián)對象來解決下。

一、關(guān)聯(lián)對象的常用API
  • 默認(rèn)情況下,因為分類底層結(jié)構(gòu)的限制,不能添加成員變量到分類中。但可以通過關(guān)聯(lián)對象來間接實現(xiàn)

  • 添加關(guān)聯(lián)對象

    void objc_setAssociatedObject(id object, const void * key, id value, objc_AssociationPolicy policy)
    
    • 上面方法的參數(shù)解釋

      /** 關(guān)聯(lián)對象的參數(shù)
          @param object 設(shè)置對象: 在這里是 self(類自己)
          @param key#> <#key#> description#>
          @param value#> 關(guān)聯(lián)值:這里是 name
          @param policy#> 關(guān)聯(lián)策略
          @return
      */
       /**  關(guān)聯(lián)策略(objc_AssociationPolicy)                     對應(yīng)的修飾符
          OBJC_ASSOCIATION_ASSIGN = 0,                          assign
          OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1                 strong, nonatomic
          OBJC_ASSOCIATION_COPY_NONATOMIC = 3,                  copy, nonatomic
          OBJC_ASSOCIATION_RETAIN = 01401,                      strong, atomic
          OBJC_ASSOCIATION_COPY = 01403                         copy, atomic
        */
      
  • 獲得關(guān)聯(lián)對象

    id objc_getAssociatedObject(id object, const void * key)
    
  • 移除所有的關(guān)聯(lián)對象

    void objc_removeAssociatedObjects(id object)
    
二、關(guān)聯(lián)對象的實際運用中的Key

static : 代表只能在此文件內(nèi)訪問
說明添加幾個成員變量就要寫幾個關(guān)聯(lián)對象的Key
下面四種關(guān)聯(lián)對象的實際使用的demo

  • 2.1、賦值的key :static void *MyKey = &MyKey;

    static void *MyKey = &MyKey;
     // 關(guān)聯(lián)對象
    objc_setAssociatedObject(obj, MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
     // 獲得關(guān)聯(lián)對象
    objc_getAssociatedObject(obj, MyKey)
    

    demo查看JKPerson+Test

  • 2.2、內(nèi)存地址的key : static char MyKey;

    static char MyKey;
    objc_setAssociatedObject(obj, &MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    objc_getAssociatedObject(obj, &MyKey)
    

    const void * _Nonnull key: 僅僅是一個指針,&MyKey地址就可以, static char MyKey;不是一定要用char,這里只是它的字節(jié)是一個字節(jié),在此僅僅只傳一個指針而已
    demo查看JKPerson+Test2

  • 2.3、使用屬性名作為key : #define JKRevelKey @"revel";

    NSArray *str = @"revel";: 其實@"revel"就是自身的內(nèi)存地址:唯一性,可以打印 str,內(nèi)存地址是一樣的

    objc_setAssociatedObject(obj, @"property", value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    objc_getAssociatedObject(obj, @"property");
    

    demo查看JKPerson+Test3

  • 2.4、使用get方法的@selecor作為key

    可以使用_cmd來代替@selector(getter)

    objc_setAssociatedObject(obj, @selector(getter), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    objc_getAssociatedObject(obj, @selector(getter))
    

    demo查看JKPerson+Test4

三、關(guān)聯(lián)對象的原理探索
  • 3.1、實現(xiàn)關(guān)聯(lián)對象技術(shù)的核心對象有

    AssociationsManager

    Class  AssociationsManager {
       static AssociationsHashMap *_map;
    };
    

    AssociationsHashMap

    class AssociationsHashMap : public unordered_map<disguised_ptr_t, ObjectAssociationMap *, DisguisedPointerHash, DisguisedPointerEqual, AssociationsHashMapAllocator> 
    

    ObjectAssociationMap

    class ObjectAssociationMap : public std::map<void *, ObjcAssociation, ObjectPointerLess, ObjectAssociationMapAllocator>
    

    ObjcAssociation

    class ObjcAssociation {
       uintptr_t _policy;
       id _value;
    }
    
  • 3.2、下面圖表述了上面四個核心對象的關(guān)系

    關(guān)聯(lián)對象技術(shù)的核心對象的關(guān)系
  • 3.3、移除關(guān)聯(lián)對象移除所有的關(guān)聯(lián)對象

    • 移除關(guān)聯(lián)對象

      person2.degree = nil;
      
    • 移除所有的關(guān)聯(lián)對象

      void objc_removeAssociatedObjects(id object)
      
    • 可以查看demo里面的ViewController中的test5方法:當(dāng)object 被移除的同時對應(yīng)上面的AssociationsHashMap也會被對應(yīng)的移除,字典(看到Map可以當(dāng)做字典來看待)是一對一的關(guān)系。

?著作權(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)容