category添加成員變量(關(guān)聯(lián)對(duì)象)及原理

實(shí)現(xiàn)

category無(wú)法添加成員變量,category編譯之后,會(huì)生成struct _category_t類(lèi)型的結(jié)構(gòu)體,包含instance_methods(對(duì)象方法列表),class_methods(類(lèi)方法列表),protocols(協(xié)議列表),properties(屬性列表),沒(méi)有類(lèi)似ivars這樣的成員變量列表

struct _category_t {
    const char *name;
    struct _class_t *cls;
    const struct _method_list_t *instance_methods;
    const struct _method_list_t *class_methods;
    const struct _protocol_list_t *protocols;
    const struct _prop_list_t *properties;
};

不過(guò)我們可以通過(guò)設(shè)置關(guān)聯(lián)對(duì)象的方式添加屬性,當(dāng)我們#import <objc/runtime.h>之后,可以通過(guò)如下方法

OBJC_EXPORT void
objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key,
                         id _Nullable value, objc_AssociationPolicy policy);

OBJC_EXPORT id _Nullable
objc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key);

OBJC_EXPORT void
objc_removeAssociatedObjects(id _Nonnull object);

其中objc_AssociationPolicy為如下結(jié)構(gòu),分別對(duì)應(yīng)不同的屬性聲明(由于關(guān)聯(lián)對(duì)象是通過(guò)全局Map維護(hù),所以沒(méi)有weak聲明)

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. */
};

實(shí)現(xiàn)方式為:

//  .h文件
@property (nonatomic, copy) NSString *name;

//  .m文件
#import <objc/runtime.h>

- (void)setName:(NSString *)name {
    objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

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

原理

通過(guò)查看objc_setAssociatedObject源碼得知,有一個(gè)AssociationsManager管理關(guān)聯(lián)對(duì)象,其結(jié)構(gòu)部署為:

AssociationsManager
AssociationsHashMap
ObjectAssociationMap
ObjcAssociation
image.png
objc_setAssociatedObject(id object, const void * key, id value, objc_AssociationPolicy policy);

AssociationsManager維護(hù)著一張AssociationsHashMap結(jié)構(gòu)的HashMap,以objc_setAssociatedObject中第一個(gè)參數(shù)[object]作為key,找出對(duì)應(yīng)的ObjectAssociationMap,ObjectAssociationMap也是一個(gè)Map,以我們傳遞的第二個(gè)參數(shù)[key]作為key,找出對(duì)應(yīng)的ObjcAssociation(當(dāng)我們這個(gè)key傳遞為nil,將刪除ObjcAssociation鍵值對(duì)),這個(gè)ObjcAssociation里面維護(hù)著兩個(gè)參數(shù),就是我們傳遞的后兩個(gè)參數(shù):[value]、[policy]。取值的時(shí)候就通過(guò)兩個(gè)key,找出對(duì)應(yīng)的值

總結(jié)

category添加成員變量的實(shí)現(xiàn),實(shí)際上是通過(guò)一個(gè)雙重Map來(lái)存儲(chǔ)將要存儲(chǔ)的屬性值,第一層Map維護(hù)各個(gè)category分類(lèi)的添加成員變量的實(shí)現(xiàn),第二層Map,維護(hù)這個(gè)category中的成員變量賦值操作。

最后編輯于
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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