iOS底層學(xué)習(xí):類的擴(kuò)展和關(guān)聯(lián)對(duì)象

類的擴(kuò)展和分類

  1. category:分類、類別
  • 給類增加方法
  • 不能添加成員變量
  • 可以使用runtime給分類添加屬性
  • 分類中添加的屬性指揮生成對(duì)應(yīng)的settergetter方法的聲明,不能生成方法實(shí)現(xiàn)和帶下劃線的成員變量。
  1. extension:類擴(kuò)展
  • 可以添加成員屬性,屬于私有。
  • 可以添加方法,屬于私有。

關(guān)于類的擴(kuò)展,是放在類的聲明之后類的實(shí)現(xiàn)之前。類的擴(kuò)展里面放的多是私有方法和成員變量。類的擴(kuò)展會(huì)在編譯期就作為類的一部分寫入到類信息中。另外,類的擴(kuò)展只是一個(gè)聲明,它依賴主類需要在主類內(nèi)部完成實(shí)現(xiàn)。

關(guān)聯(lián)對(duì)象

分類不能添加屬性,它只是聲明了setter、getter方法,沒(méi)有實(shí)現(xiàn),那么就需要借助關(guān)聯(lián)對(duì)象來(lái)實(shí)現(xiàn)這個(gè)功能。

分類.h中
@property (nonatomic, copy) NSString *name;

分類.m中
- (void)setCate_name:(NSString *)name{
    /**
     (對(duì)象,標(biāo)識(shí)符,value, 策略)
     */
    objc_setAssociatedObject(self, "name", cate_name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (NSString *)name{
    return  objc_getAssociatedObject(self, "name");
}

關(guān)聯(lián)對(duì)象源碼探索

關(guān)聯(lián)對(duì)象如何運(yùn)作的

static void
_base_objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
{
  _object_set_associative_reference(object, key, value, policy);
}

static ChainedHookFunction<objc_hook_setAssociatedObject> SetAssocHook{_base_objc_setAssociatedObject};

objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
{
    SetAssocHook.get()(object, key, value, policy);
}

關(guān)聯(lián)對(duì)象設(shè)值底層調(diào)用的方法就是_object_set_associative_reference(id object, const void *key, id value, uintptr_t policy)

_object_set_associative_reference(id object, const void *key, id value, uintptr_t policy)
{
    ...
    DisguisedPtr<objc_object> disguised{(objc_object *)object};
    ObjcAssociation association{policy, value};

    association.acquireValue();
    //工作代碼塊
    {代碼塊}
    association.releaseHeldValue();
}

傳遞進(jìn)來(lái)的object被包裝成了DisguisedPtr,對(duì)應(yīng)的valuepolicy打包成了ObjcAssociation。
然后具體的操作放在了代碼塊中

    association.acquireValue();
{
        AssociationsManager manager;
    
        AssociationsHashMap &associations(manager.get());

        if (value) {
            auto refs_result = associations.try_emplace(disguised, ObjectAssociationMap{});
            if (refs_result.second) {
                /* it's the first association we make */
                object->setHasAssociatedObjects();
            }

            /* establish or replace the association */
            auto &refs = refs_result.first->second; // 空的桶子
            auto result = refs.try_emplace(key, std::move(association));
            if (!result.second) {
                association.swap(result.first->second);
            }
        } else {
            auto refs_it = associations.find(disguised);
            if (refs_it != associations.end()) {
                auto &refs = refs_it->second;
                auto it = refs.find(key);
                if (it != refs.end()) {
                    association.swap(it->second);
                    refs.erase(it);
                    if (refs.size() == 0) {
                        associations.erase(refs_it);

                    }
                }
            }
        }
    }
  • acquireValue() 更具傳遞進(jìn)來(lái)的polic對(duì)值進(jìn)行處理
inline void acquireValue() {
        if (_value) {
            switch (_policy & 0xFF) {
            case OBJC_ASSOCIATION_SETTER_RETAIN:
                _value = objc_retain(_value);
                break;
            case OBJC_ASSOCIATION_SETTER_COPY:
                _value = ((id(*)(id, SEL))objc_msgSend)(_value, @selector(copy));
                break;
            }
        }
    }

基本流程:
1:創(chuàng)建一個(gè) AssociationsManager 管理類。
2:拿到一張全局唯一的:AssociationsHashMap。
3:判斷是否插入的關(guān)聯(lián)值value是否存在,存在走第4步,不存在則會(huì)移除關(guān)聯(lián)對(duì)象。
4:try_emplace,并創(chuàng)建一個(gè)空的 ObjectAssociationMap 去取查詢的鍵值對(duì):
5:如果發(fā)現(xiàn)沒(méi)有這個(gè) key 就插入一個(gè) 空的 BucketT進(jìn)去并返回true
6:通過(guò)setHasAssociatedObjects方法標(biāo)記對(duì)象存在關(guān)聯(lián)對(duì)象即置isa指針的has_assoc屬性為true
7:用當(dāng)前 policy 和 value 組成了一個(gè) ObjcAssociation 替換原來(lái) BucketT 中的空
8:標(biāo)記一下 ObjectAssociationMap 的第一次為 false

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

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

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