前言
rwe什么时候有值,分类attachCategories加载时有
补充
承接上篇类的加载原理(上)内容
readClass中调用了addNamedClass,而addNamedClass调用了NXMapInsert,NXMapInsert为在table表中以key(类名)-value(地址)形式插入,此步骤也仅是可以通过名字拿到类地址,具体类是如何加载的呢?static void addNamedClass(Class cls, const char *name, Class replacing = nil){runtimeLock.assertLocked();Class old;if ((old = getClassExceptSomeSwift(name)) && old != replacing) {inform_duplicate(name, old, cls);// getMaybeUnrealizedNonMetaClass uses name lookups.// Classes not found by name lookup must be in the// secondary meta->nonmeta table.addNonMetaClass(cls);} else {NXMapInsert(gdb_objc_realized_classes, name, cls);}ASSERT(!(cls->data()->flags & RO_META));// wrong: constructed classes are already realized when they get here// ASSERT(!cls->isRealized());}
void *NXMapInsert(NXMapTable *table, const void *key, const void *value)
类处理流程-重点
map_images -> map_images_nolock -> _read_images

read_class在非懒加载类列表处理过程中,调用了realizeClassWithoutSwift,在类的慢速查找lookupImpOrForward中也会调用这个函数,所以realizeClassWithoutSwift是核心
// Realize non-lazy classes (for +load methods and static instances)for (EACH_HEADER) {classref_t const *classlist = hi->nlclslist(&count);for (i = 0; i < count; i++) {Class cls = remapClass(classlist[i]);if (!cls) continue;addClassTableEntry(cls);if (cls->isSwiftStable()) {if (cls->swiftMetadataInitializer()) {_objc_fatal("Swift class %s with a metadata initializer ""is not allowed to be non-lazy",cls->nameForLogging());}// fixme also disallow relocatable classes// We can't disallow all Swift classes because of// classes like Swift.__EmptyArrayStorage}realizeClassWithoutSwift(cls, nil);}}
realizeClassWithoutSwift
流程图-类的加载
lookUpImpOrForward慢速查找也会调用realizeClassWithoutSwift方法
- 读取data,创建ro

查看ro的内存结构
- 在
auto ro = (constclass_ro_t *)cls->data()处下断点,查看ro的内存结构,此时ro只有一个地址,其baseMethodList等还是没有具体的数据 - 类别买了房子,只写了名字,家具(有地址了)还没有放入
具体是在methodizeClass -> prepareMethodLists -> fixupMethodList(name, addr)加入到方法列表中,再根据地址排序
(lldb) p ro(const class_ro_t *) $0 = 0x00000001000082f0(lldb) p *$0(const class_ro_t) $1 = {flags = 0instanceStart = 8instanceSize = 8reserved = 0= {ivarLayout = 0x0000000000000000nonMetaclass = nil}name = {std::__1::atomic<const char *> = "CCPerson" {Value = 0x0000000100003f5f "CCPerson"}}baseMethodList = 0x0000000100008338baseProtocols = nilivars = nilweakIvarLayout = 0x0000000000000000baseProperties = nil_swiftMetadataInitializer_NEVER_USE = {}}
ro复制到rw
ro->rw的真正复制是在此时实现
- rw = objc::zalloc
(); - rw->set_ro(ro);
- rw->flags = RW_REALIZED|RW_REALIZING|isMeta;
- cls->setData(rw);
if (ro->flags & RO_FUTURE) {// This was a future class. rw data is already allocated.rw = cls->data();ro = cls->data()->ro();ASSERT(!isMeta);cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);} else {// Normal class. Allocate writeable class data.rw = objc::zalloc<class_rw_t>();rw->set_ro(ro);rw->flags = RW_REALIZED|RW_REALIZING|isMeta;cls->setData(rw);}
元类设置
- rw = objc::zalloc
如果是元类,从NonpointerIsa其不需要任何信息,所以可以设置setInstancesRequireRawIsa为yes,当前前类在retain或release效率会更高
如果不是元类,但在环境变量中禁用了NonpointerIsa,同样其instancesRequireRawIsa为yes,提高效率
if (isMeta) {// Metaclasses do not need any features from non pointer ISA// This allows for a faspath for classes in objc_retain/objc_release.cls->setInstancesRequireRawIsa();} else {// Disable non-pointer isa for some classes and/or platforms.// Set instancesRequireRawIsa.bool instancesRequireRawIsa = cls->instancesRequireRawIsa();bool rawIsaIsInherited = false;static bool hackedDispatch = false;if (DisableNonpointerIsa) {// Non-pointer isa disabled by environment or app SDK versioninstancesRequireRawIsa = true;}...}
继承链设置
cls->setSuperclass(supercls);cls->initClassIsa(metacls);
C++构造函数设置
```cpp if (ro->flags & RO_HAS_CXX_STRUCTORS) {
cls->setHasCxxDtor();if (! (ro->flags & RO_HAS_CXX_DTOR_ONLY)) {cls->setHasCxxCtor();}
}
<a name="LK3Kk"></a>#### 建立类、子类的关系链表```cpp// Connect this class to its superclass's subclass listsif (supercls) {addSubclass(supercls, cls);} else {addRootClass(cls);}
添加类
methodizeClass(cls, previously);
methodizeClass
添加类是在methodizeClass中处理
- 通过ro->baseMethods()获取methodList
- 如果存在list则进入prepareMethodLists
- prepareMethodList又会调用fixupMethodList
fixupMethodList
- 遍历methodLlist,将其sel取出设置到sel_registerNameNoLock(已注册类)中
- SortBySELAddress,根据地址排序方法Sort by selector address. ```cpp static void fixupMethodList(method_list_t *mlist, bool bundleCopy, bool sort) { runtimeLock.assertLocked(); ASSERT(!mlist->isFixedUp());
// fixme lock less in attachMethodLists ? // dyld3 may have already uniqued, but not sorted, the list if (!mlist->isUniqued()) { mutex_locker_t lock(selLock);
// Unique selectors in list. for (auto& meth : *mlist) {
const char *name = sel_cname(meth.name());meth.setName(sel_registerNameNoLock(name, bundleCopy));
} }
// Sort by selector address. // Don’t try to sort small lists, as they’re immutable. // Don’t try to sort big lists of nonstandard size, as stable_sort // won’t copy the entries properly. if (sort && !mlist->isSmallList() && mlist->entsize() == method_t::bigSize) { method_t::SortBySELAddress sorter; std::stable_sort(&mlist->begin()->big(), &mlist->end()->big(), sorter); }
// Mark method list as uniqued and sorted. // Can’t mark small lists, since they’re immutable. if (!mlist->isSmallList()) { mlist->setFixedUp(); } } ```
懒加载类和非懒加载类->load
赖加载类,使用时再加载,节约内存,增加编译速度 ——> 按需加载
- 如果类实现了+load方法,则就会走非懒加载类流程,进行上述类流程处理图,是一个耗时操作
- 只有类或者其分类都未实现load方法,则类的加载会在其第一次发送消息时处理,通过lookupImpOrForward->realizeClassWithoutSwift
- 将类中+load方法屏蔽,后在realizeClassWithoutSwift断点调试,可以验证此函数调用流程
分类
本质探索
在main函数中添加CCPerson的分类
- clang -rewrite-objc main.m -o main.cpp 编译后的到CPP文件
分类CCPerson(CC)被编译为_category_t结构体
static struct _category_t *L_OBJC_LABEL_CATEGORY_$ [1] __attribute__((used, section ("__DATA, __objc_catlist,regular,no_dead_strip")))= {&_OBJC_$_CATEGORY_CCPerson_$_CC,};
分类也是一个结构体类型
- name,就是CC
- cls,类名
- instance_methods,class_methods 分类没有元类,所以这里有两个参数,在attachToClass中同样有两个调用方法
- attachCategories(cls, list.array(), list.count(), otherFlags | ATTACH_CLASS);
- attachCategories(cls->ISA(), list.array(), list.count(), otherFlags | ATTACH_METACLASS);
- protocols,协议,
- properties, 属性,
- 无set、get方法,通过关联对象来添加属性
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;};
此时是编译文件,还没有运行时,所以name等信息还不知道
static struct _category_t _OBJC_$_CATEGORY_CCPerson_$_CC __attribute__ ((used, section ("__DATA,__objc_const"))) ={"CCPerson",0, // &OBJC_CLASS_$_CCPerson,(const struct _method_list_t *)&_OBJC_$_CATEGORY_INSTANCE_METHODS_CCPerson_$_CC,(const struct _method_list_t *)&_OBJC_$_CATEGORY_CLASS_METHODS_CCPerson_$_CC,0,(const struct _prop_list_t *)&_OBJC_$_PROP_LIST_CCPerson_$_CC,};
引入 - categories
添加分类时,rwe可以赋上值,核心重点attachCategories
methodizeClass()函数中,rwe存在时,才会调用attachToClass,而rwe是否存在取决于extAllocIfNeeded函数
- extAllocIfNeeded全局搜索,都与runtime有关,都是在运行时加载
- 调起attachCategories的地方
- load_categories_nolock -> attachCategories
- attachToClass -> attachCategories
class_rw_ext_t *extAllocIfNeeded() {auto v = get_ro_or_rwe();if (fastpath(v.is<class_rw_ext_t *>())) {return v.get<class_rw_ext_t *>(&ro_or_rw_ext);} else {return extAlloc(v.get<const class_ro_t *>(&ro_or_rw_ext));}}


