前言
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 = 0
instanceStart = 8
instanceSize = 8
reserved = 0
= {
ivarLayout = 0x0000000000000000
nonMetaclass = nil
}
name = {
std::__1::atomic<const char *> = "CCPerson" {
Value = 0x0000000100003f5f "CCPerson"
}
}
baseMethodList = 0x0000000100008338
baseProtocols = nil
ivars = nil
weakIvarLayout = 0x0000000000000000
baseProperties = 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 version
instancesRequireRawIsa = 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 lists
if (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));
}
}