接着往下看 load_categories_nolock
static void load_categories_nolock(header_info *hi) { bool hasClassProperties = hi->info()->hasCategoryClassProperties(); size_t count; auto processCatlist = [&](category_t * const *catlist) { for (unsigned i = 0; i < count; i++) { category_t *cat = catlist; Class cls = remapClass(cat->cls); locstamped_category_t lc{cat, hi}; if (!cls) { // Category's target class is missing (probably weak-linked). // Ignore the category. if (PrintConnecting) { _objc_inform("CLASS: IGNORING category \?\?\?(%s) %p with " "missing weak-linked target class", cat->name, cat); } continue; } // Process this category. if (cls->isStubClass()) { // Stub classes are never realized. Stub classes // don't know their metaclass until they're // initialized, so we have to add categories with // class methods or properties to the stub itself. // methodizeClass() will find them and add them to // the metaclass as appropriate. if (cat->instanceMethods || cat->protocols || cat->instanceProperties || cat->classMethods || cat->protocols || (hasClassProperties && cat->_classProperties)) { objc::unattachedCategories.addForClass(lc, cls); } } else { // First, register the category with its target class. // Then, rebuild the class's method lists (etc) if // the class is realized. if (cat->instanceMethods || cat->protocols || cat->instanceProperties) { if (cls->isRealized()) { attachCategories(cls, &lc, 1, ATTACH_EXISTING); } else { objc::unattachedCategories.addForClass(lc, cls); } } if (cat->classMethods || cat->protocols || (hasClassProperties && cat->_classProperties)) { if (cls->ISA()->isRealized()) { //把分类中声明的属性,方法添加到累的属性,方法列表中 attachCategories(cls->ISA(), &lc, 1, ATTACH_EXISTING | ATTACH_METACLASS); } else { //把当前分类加载到对应的类中 objc::unattachedCategories.addForClass(lc, cls->ISA()); //addForClass底层数据结构的映射 } } } } }; //读取分类列表 processCatlist(hi->catlist(&count)); processCatlist(hi->catlist2(&count));}在这个函数中做了三件事
@interface Person : NSObject@property (nonatomic, copy) NSString *name;@end在类中声明一个属性,体系会主动帮我们生成getter setter ivar.
当我们利用分类想为原类添加属性时,我们则须要利用关联对象的方式,那么关联对象和直接声明数据原理是否一样呢,我们接下来分析下
分类中我们利用objc_setAssociatedObject,objc_getAssociatedObject这两函数添加属性
起首我们来看下关联对象怎么存的objc_setAssociatedObject
void_object_set_associative_reference(id object, const void *key, id value, uintptr_t policy){ // This code used to work when nil was passed for object and key. Some code // probably relies on that to not crash. Check and handle it explicitly. // rdar://problem/44094390 if (!object && !value) return; if (object->getIsa()->forbidsAssociatedObjects()) _objc_fatal("objc_setAssociatedObject called on instance (%p) of class %s which does not allow associated objects", object, object_getClassName(object)); DisguisedPtr<objc_object> disguised{(objc_object *)object}; ObjcAssociation association{policy, value}; //把外部传入的value和战略存起来 // retain the new value (if any) outside the lock. //根据上面存的policy,设置内存管理语义 association.acquireValue(); bool isFirstAssociation = false; { AssociationsManager manager; //声明一个管理者,用来管理下面的AssociationsHashMap AssociationsHashMap &associations(manager.get()); if (value) { //<first, second> -> <disguised, ObjectAssociationMap{}> auto refs_result = associations.try_emplace(disguised, ObjectAssociationMap{}); if (refs_result.second) { /* it's the first association we make */ isFirstAssociation = true; } /* 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); } } } } } // Call setHasAssociatedObjects outside the lock, since this // will call the object's _noteAssociatedObjects method if it // has one, and this may trigger +initialize which might do // arbitrary stuff, including setting more associated objects. if (isFirstAssociation) object->setHasAssociatedObjects(); // release the old value (outside of the lock). association.releaseHeldValue();}