前言
前篇 我们了解到 应用的加载流程,在
main
函数调用之前有许多系统的操作流程,但是在分析类的加载需要明确的是main
函数才是我们app
程序的入口函数,我们知道 在执行main
函数之前,系统会对runtime
进行初始化,在之前我们了解到dyld
会调用runtime
的入口函数,runtime
的入口函数 就是_objc_iinnit
,它就是在mian
函数之前就被dyld
调用,而load
方法就在_objc_init
中调用,所以 我们探究的起点就是_objc_init
函数
一 _objc_init 探究分析
我们在runtime的源码中 可以了解到_objc_init 的源代码
/***********************************************************************
* _objc_init
* Bootstrap initialization. Registers our image notifier with dyld.
* Called by libSystem BEFORE library initialization time
**********************************************************************/
void _objc_init(void)
{
static bool initialized = false;
if (initialized) return;
initialized = true;
// fixme defer initialization until an objc-using image is found?
environ_init(); // 环境变量
tls_init(); //线程 key 的绑定
static_init(); //初始化系统内置的 C++ 静态构造函数
runtime_init(); //主要是运行时的初始化,主要分为两部分:分类初始化(unattachedCategories)和类的表初始化(allocatedClasses)
exception_init(); // 初始化libobjc异常处理
cache_init(); //缓存初始化
_imp_implementationWithBlock_init(); //启动机制回调
// 注册回调通知
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
#if __OBJC2__
didCallDyldNotifyRegister = true;
#endif
}·
二 _dyld_objc_notify_register 解析
//
// Note: only for use by objc runtime
// Register handlers to be called when objc images are mapped, unmapped, and initialized.
// Dyld will call back the "mapped" function with an array of images that contain an objc-image-info section.
// Those images that are dylibs will have the ref-counts automatically bumped, so objc will no longer need to
// call dlopen() on them to keep them from being unloaded. During the call to _dyld_objc_notify_register(),
// dyld will call the "mapped" function with already loaded objc images. During any later dlopen() call,
// dyld will also call the "mapped" function. Dyld will call the "init" function when dyld would be called
// initializers in that image. This is when objc calls any +load methods in that image.
//
// 翻译如下:
// 注意: 只能在objc runtime 中使用
// 注册回调函数, 当 objc 库 映射,未映射,和初始化的时候调用
// dyld将要调用包含objc-image-info的镜像数组回调的“mapped”函数。
// dyld 会为这些镜像自动增加引用技术,所以objc 不需要使用dlopen函数保证它不被卸载。
// 在调用 `_dyld_objc_notify_register` 的过程中,dyld 会调用已经加载的镜像的 mapped 函数
// 在之后的任何dlopen()调用期间,dyld也将调用“映射”函数。
// 在dyld 调用镜像的initializers 的时候,dyld 将调用 init
// 这是objc在这个镜像中调用所有+ load方法的时候。
void _dyld_objc_notify_register(_dyld_objc_notify_mapped mapped,
_dyld_objc_notify_init init,
_dyld_objc_notify_unmapped unmapped);
_dyld_objc_notify_register 实现
void _dyld_objc_notify_register(_dyld_objc_notify_mapped mapped,
_dyld_objc_notify_init init,
_dyld_objc_notify_unmapped unmapped)
{
dyld::registerObjCNotifiers(mapped, init, unmapped);
}
注册回调通知
参数介绍
- _dyld_objc_notify_mapped : dyld 将 image 加载进内存时 , 会触发该函数.
- _dyld_objc_notify_init : dyld 初始化 image 会触发该方法. ( 我们所熟知的 load 方法也是在此处调用 ) .
- unmap__dyld_objc_notify_unmapped: dyld 将 image 移除时 , 会触发该函数 .
这三个回调函数 在runtime 中分别对应着 map_images, load_images, unmap_image
三 map_images 将image 加载进内存回调
- map_images
/***********************************************************************
* map_images
* Process the given images which are being mapped in by dyld.
* Calls ABI-agnostic code after taking ABI-specific locks.
*
* Locking: write-locks runtimeLock
**********************************************************************/
void
map_images(unsigned count, const
char * const paths[],
const struct mach_header * const mhdrs[])
{
mutex_locker_t lock(runtimeLock);
return map_images_nolock(count, paths, mhdrs);
}
map_images 方法在 image 加载到内存的时候会触发该方法的调用
- map_images_nolock
void
map_images_nolock(unsigned mhCount, const char * const mhPaths[],
const struct mach_header * const mhdrs[])
{
... 代码省略
if (hCount > 0) {
// 读取镜像文件
_read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
}
firstTime = NO;
// Call image load funcs after everything is set up.
for (auto func : loadImageFuncs) {
for (uint32_t i = 0; i < mhCount; i++) {
func(mhdrs[i]);
}
}
}
四 _read_images 读取镜像
主要内容是:条件控制只执行一次、处理编译阶段SEL混乱的问题、错误的类处理、加载协议、分类处理、类的读取、以及针对某些非懒加载的在直接进行实现。
我们现在分段进行解析,通过 ts.log
进行分段分析
4.1 创建表
... 省略
if (!doneOnce) {
doneOnce = YES;
...省略
// namedClasses
// Preoptimized classes don't go in this table.
// 4/3 is NXMapTable's load factor
int namedClassesSize =
(isPreoptimized() ? unoptimizedTotalClasses : totalClasses) * 4 / 3;
// 实例化存储类的哈希表
gdb_objc_realized_classes =
NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);
ts.log("IMAGE TIMES: first time tasks");
}
- gdb_objc_realized_classes存储不在共享缓存且已命名的所有类,其容量是类数量的4/3
// This is a misnomer: gdb_objc_realized_classes is actually a list of
// named classes not in the dyld shared cache, whether realized or not.
NXMapTable *gdb_objc_realized_classes; // exported for debuggers in objc-gdb.h
4.2 sel_registerNameNoLock 处理编译阶段SEL混乱的问题
// 修复预编译阶段的@selector的混乱问题
static size_t UnfixedSelectors;
{
mutex_locker_t lock(selLock);
for (EACH_HEADER) {
if (hi->hasPreoptimizedSelectors()) continue;
bool isBundle = hi->isBundle();
// 从macho 文件中 获取方法名称
SEL *sels = _getObjc2SelectorRefs(hi, &count);
UnfixedSelectors += count;
for (i = 0; i < count; i++) {
// sel_cname 将 SEL 强转为 char 类型
const char *name = sel_cname(sels[i]);
// 注册 SEL 的操作
SEL sel = sel_registerNameNoLock(name, isBundle);
if (sels[i] != sel) {
sels[i] = sel;
}
}
}
}
ts.log("IMAGE TIMES: fix up selector references");
-
_getObjc2SelectorRefs
:其中_getObjc2SelectorRefs
的源码如下,表示获取Mach-O中的静态段__objc_selrefs
// function name content type section name
GETSECT(_getObjc2SelectorRefs, SEL, "__objc_selrefs");
GETSECT(_getObjc2MessageRefs, message_ref_t, "__objc_msgrefs");
GETSECT(_getObjc2ClassRefs, Class, "__objc_classrefs");
GETSECT(_getObjc2SuperRefs, Class, "__objc_superrefs");
GETSECT(_getObjc2ClassList, classref_t const, "__objc_classlist");
GETSECT(_getObjc2NonlazyClassList, classref_t const, "__objc_nlclslist");
GETSECT(_getObjc2CategoryList, category_t * const, "__objc_catlist");
GETSECT(_getObjc2CategoryList2, category_t * const, "__objc_catlist2");
GETSECT(_getObjc2NonlazyCategoryList, category_t * const, "__objc_nlcatlist");
GETSECT(_getObjc2ProtocolList, protocol_t * const, "__objc_protolist");
GETSECT(_getObjc2ProtocolRefs, protocol_t *, "__objc_protorefs");
GETSECT(getLibobjcInitializers, UnsignedInitializer, "__objc_init_func");
-
sel_cname
:其中SEL --> sel
并不是简单的字符串,是带地址的字符串 如下所示,sels[i]与sel字符串一致,但是地址不一致,所以需要调整为一致的。即fix up
4.3 readClass 重点
// Discover classes. Fix up unresolved future classes. Mark bundle classes.
bool hasDyldRoots = dyld_shared_cache_some_image_overridden();
// 从编译后的类列表中取出所有类,获取到的是一个classref_t类型的指针
for (EACH_HEADER) {
if (! mustReadClasses(hi, hasDyldRoots)) {
// Image is sufficiently optimized that we need not call readClass()
// 镜像充分优化,我们不需要调用 readClass()
continue;
}
classref_t const *classlist = _getObjc2ClassList(hi, &count);
bool headerIsBundle = hi->isBundle();
bool headerIsPreoptimized = hi->hasPreoptimizedClasses();
for (i = 0; i < count; i++) {
//数组中会取出OS_dispatch_queue_concurrent、OS_xpc_object、NSRunloop等系统类,例如CF、Fundation、libdispatch中的类。以及自己创建的类
Class cls = (Class)classlist[i];
// 通过 readClass 函数获取处理后的新类,内部主要操作 ro 和 rw 结构体
Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
// 初始化所有懒加载的类需要的内存空间,并将所有的未来需要处理的类添加到一个数组中
// 现在数据没有加载到的,连类都没有初始化
if (newCls != cls && newCls) {
// Class was moved but not deleted. Currently this occurs
// only when the new class resolved a future class.
// Non-lazily realize the class below.
resolvedFutureClasses = (Class *)
realloc(resolvedFutureClasses,
(resolvedFutureClassCount+1) * sizeof(Class));
resolvedFutureClasses[resolvedFutureClassCount++] = newCls;
}
}
}
ts.log("IMAGE TIMES: discover classes");
- read_class
/***********************************************************************
* readClass
* Read a class and metaclass as written by a compiler.
* Returns the new class pointer. This could be:
* - cls
* - nil (cls has a missing weak-linked superclass)
* - something else (space for this class was reserved by a future class)
*
* Note that all work performed by this function is preflighted by
* mustReadClasses(). Do not change this function without updating that one.
*
* Locking: runtimeLock acquired by map_images or objc_readClassPair
**********************************************************************/
Class readClass(Class cls, bool headerIsBundle, bool headerIsPreoptimized)
{
// 已经实现类从内存中读取,未实现的类从 mach-o 中读取
const char *mangledName = cls->mangledName();
// 测试代码
const char *LGPersonName = "LGPerson";
if (strcmp(mangledName, LGPersonName) == 0) {
printf("%s ---- %s",__func__ , mangledName);
}
// 如果某个 cls 的 superclass 是 weak-linked 的并且丢失了,则返回YES。
if (missingWeakSuperclass(cls)) {
// No superclass (probably weak-linked).
// Disavow any knowledge of this subclass.
if (PrintConnecting) {
_objc_inform("CLASS: IGNORING class '%s' with "
"missing weak-linked superclass",
cls->nameForLogging());
}
// 添加到重映射表里面,映射为 nil
addRemappedClass(cls, nil);
cls->superclass = nil;
return nil;
}
cls->fixupBackwardDeployingStableSwift();
Class replacing = nil;
if (Class newCls = popFutureNamedClass(mangledName)) {
// This name was previously allocated as a future class.
// Copy objc_class to future class's struct.
// Preserve future's rw data block.
if (newCls->isAnySwift()) {
_objc_fatal("Can't complete future class request for '%s' "
"because the real class is too big.",
cls->nameForLogging());
}
class_rw_t *rw = newCls->data();
const class_ro_t *old_ro = rw->ro();
memcpy(newCls, cls, sizeof(objc_class));
rw->set_ro((class_ro_t *)newCls->data());
newCls->setData(rw);
freeIfMutable((char *)old_ro->name);
free((void *)old_ro);
addRemappedClass(cls, newCls);
replacing = cls;
cls = newCls;
}
if (headerIsPreoptimized && !replacing) {
// class list built in shared cache
// fixme strict assert doesn't work because of duplicates
// ASSERT(cls == getClass(name));
ASSERT(getClassExceptSomeSwift(mangledName));
} else {
// 重点:从mach-o 文件读取插入到这两个表里面,自此在内存中就可以读到这个类了
// 将 cls 加入到 gdb_objc_realized_classes 表里面去
addNamedClass(cls, mangledName, replacing);
// 将 cls 插入到 allocatedClasses 表里面去
addClassTableEntry(cls);
}
// for future reference: shared cache never contains MH_BUNDLEs
if (headerIsBundle) {
cls->data()->flags |= RO_FROM_BUNDLE;
cls->ISA()->data()->flags |= RO_FROM_BUNDLE;
}
// 返回这个类
return cls;
}
- addNamedClass
将当前类添加到已创建好的gdb_objc_realized_classes哈希表(存放所有类)
/***********************************************************************
* addNamedClass
* Adds name => cls to the named non-meta class map.
* Warns about duplicate class names and keeps the old mapping.
* Locking: runtimeLock must be held by the caller
**********************************************************************/
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());
}
- addClassTableEntry
当前类已经初始化,所以要添加到allocatedClasses哈希表,并添加元类
/***********************************************************************
* addClassTableEntry
* Add a class to the table of all classes. If addMeta is true,
* automatically adds the metaclass of the class as well.
* Locking: runtimeLock must be held by the caller.
**********************************************************************/
static void
addClassTableEntry(Class cls, bool addMeta = true)
{
runtimeLock.assertLocked();
// This class is allowed to be a known class via the shared cache or via
// data segments, but it is not allowed to be in the dynamic table already.
// 将本类 和 元类添加到类表中
auto &set = objc::allocatedClasses.get();
ASSERT(set.find(cls) == set.end());
// 未识别的类
if (!isKnownClass(cls))
set.insert(cls);
if (addMeta)
addClassTableEntry(cls->ISA(), false);
// 开辟空间-元类递归-元类开辟空间-元类名称插入类表
}
- 注意:
第三步 类处理(readClass)中 内部并没有完成类的加载,只是将类名 和 类地址 记录到了类表中
4.4 修复重映射
// 将未映射Class和Super Class重映射,被remap的类都是非懒加载的类
// Fix up remapped classes
// Class list and nonlazy class list remain unremapped.
// Class refs and super refs are remapped for message dispatching.
if (!noClassesRemapped()) {
for (EACH_HEADER) {
// 重映射Class,注意是从_getObjc2ClassRefs函数中取出类的引用
Class *classrefs = _getObjc2ClassRefs(hi, &count);
for (i = 0; i < count; i++) {
remapClassRef(&classrefs[i]);
}
// fixme why doesn't test future1 catch the absence of this?
classrefs = _getObjc2SuperRefs(hi, &count);
for (i = 0; i < count; i++) {
remapClassRef(&classrefs[i]);
}
}
}
ts.log("IMAGE TIMES: remap classes");
4.5 fixupMessageRef: 修复旧的函数指针调用遗留
// Fix up old objc_msgSend_fixup call sites
for (EACH_HEADER) {
message_ref_t *refs = _getObjc2MessageRefs(hi, &count);
if (count == 0) continue;
if (PrintVtables) {
_objc_inform("VTABLES: repairing %zu unsupported vtable dispatch "
"call sites in %s", count, hi->fname());
}
for (i = 0; i < count; i++) {
// 内部将常用的alloc、objc_msgSend等函数指针进行注册,并fix为新的函数指针
fixupMessageRef(refs+i);
}
}
ts.log("IMAGE TIMES: fix up objc_msgSend_fixup");
4.6 readProtocol :读取并初始化Protocol
bool cacheSupportsProtocolRoots = sharedCacheSupportsProtocolRoots();
// Discover protocols. Fix up protocol refs.
// 遍历所有协议列表,并且将协议列表加载到Protocol的哈希表中
for (EACH_HEADER) {
extern objc_class OBJC_CLASS_$_Protocol;
// 获取协议类 cls = Protocol类
Class cls = (Class)&OBJC_CLASS_$_Protocol;
ASSERT(cls);
// 获取protocol哈希表
NXMapTable *protocol_map = protocols();
bool isPreoptimized = hi->hasPreoptimizedProtocols();
// Skip reading protocols if this is an image from the shared cache
// and we support roots
// Note, after launch we do need to walk the protocol as the protocol
// in the shared cache is marked with isCanonical() and that may not
// be true if some non-shared cache binary was chosen as the canonical
// definition
if (launchTime && isPreoptimized && cacheSupportsProtocolRoots) {
if (PrintProtocols) {
_objc_inform("PROTOCOLS: Skipping reading protocols in image: %s",
hi->fname());
}
continue;
}
bool isBundle = hi->isBundle();
// 从编译器中读取并初始化Protocol
protocol_t * const *protolist = _getObjc2ProtocolList(hi, &count);
for (i = 0; i < count; i++) {
readProtocol(protolist[i], cls, protocol_map,
isPreoptimized, isBundle);
}
ts.log("IMAGE TIMES: discover protocols");
4.7 修复协议列表引用
// Fix up @protocol references
// Preoptimized images may have the right
// answer already but we don't know for sure.
// 修复协议列表引用,优化后的images可能是正确的,但是并不确定
for (EACH_HEADER) {
// At launch time, we know preoptimized image refs are pointing at the
// shared cache definition of a protocol. We can skip the check on
// launch, but have to visit @protocol refs for shared cache images
// loaded later.
if (launchTime && cacheSupportsProtocolRoots && hi->isPreoptimized())
continue;
// 需要注意到是,下面的函数是_getObjc2ProtocolRefs,和上面的_getObjc2ProtocolList不一样
protocol_t **protolist = _getObjc2ProtocolRefs(hi, &count);
for (i = 0; i < count; i++) {
remapProtocolRef(&protolist[i]);
}
}
ts.log("IMAGE TIMES: fix up @protocol references");
4.8 分类的加载
// Discover categories. Only do this after the initial category
// attachment has been done. For categories present at startup,
// discovery is deferred until the first load_images call after
// the call to _dyld_objc_notify_register completes. rdar://problem/53119145
// 发现分类。仅在完成初始类别附件后才执行此操作。 对于启动时出现的类别,发现将推迟到对_dyld_objc_notify_register的调用完成后的第一个load_images调用为止。
if (didInitialAttachCategories) {
for (EACH_HEADER) {
load_categories_nolock(hi);
}
}
ts.log("IMAGE TIMES: discover categories");
4.9 非懒加载的类
非懒加载类定义:实现了+load方法 和 静态初始化的类是非懒加载类,否则就是懒加载类
// Category discovery MUST BE Late to avoid potential races
// when other threads call the new category code before
// this thread finishes its fixups.
// +load handled by prepare_load_methods()
// Realize non-lazy classes (for +load methods and static instances)
for (EACH_HEADER) {
classref_t const *classlist =
_getObjc2NonlazyClassList(hi, &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
}
// 实现所有非懒加载的类(实例化类对象的一些信息,例如rw)
realizeClassWithoutSwift(cls, nil);
}
}
ts.log("IMAGE TIMES: realize non-lazy classes");
_getObjc2NonlazyClassList
获取到__objc_nlclslist,取出非懒加载类addClassTableEntry
再加载一遍——如果已添加就不会添加进去,确保整个结构都被添加realizeClassWithoutSwift
是接下来要关注的地方realizeClassWithoutSwift 分析
static Class realizeClassWithoutSwift(Class cls, Class previously)
{
runtimeLock.assertLocked();
class_rw_t *rw;
Class supercls;
Class metacls;
if (!cls) return nil;
if (cls->isRealized()) return cls;
// 判断 cls 是否已经初始化,里面是对 data()->flags 的判断
ASSERT(cls == remapClass(cls));
// fixme verify class is not in an un-dlopened part of the shared cache?
// 验证类不在共享缓存的未删除部分
auto ro = (const class_ro_t *)cls->data();
// 判断类是否是未实现的未来类
auto isMeta = ro->flags & RO_META;
if (ro->flags & RO_FUTURE) {
// 是未来的类. rw 已经被初始化
rw = cls->data();
ro = cls->data()->ro();
ASSERT(!isMeta);
// 修改 flags
cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);
} else {
// Normal class. Allocate writeable class data.
// 正常的类. 分配可写的类数据。
// 开辟 rw 内存空间
rw = objc::zalloc();
rw->set_ro(ro);
rw->flags = RW_REALIZED|RW_REALIZING|isMeta;
cls->setData(rw);
// 注: rw ro rwe
//
}
// 判断是否是元类
#if FAST_CACHE_META
if (isMeta) cls->cache.setBit(FAST_CACHE_META);
#endif
// Choose an index for this class.
// Sets cls->instancesRequireRawIsa if indexes no more indexes are available
// 设置cls->instancesRequireRawIsa如果没有更多的索引可用
cls->chooseClassArrayIndex();
if (PrintConnecting) {
_objc_inform("CLASS: realizing class '%s'%s %p %p #%u %s%s",
cls->nameForLogging(), isMeta ? " (meta)" : "",
(void*)cls, ro, cls->classArrayIndex(),
cls->isSwiftStable() ? "(swift)" : "",
cls->isSwiftLegacy() ? "(pre-stable swift)" : "");
}
// Realize superclass and metaclass, if they aren't already.
// This needs to be done after RW_REALIZED is set above, for root classes.
// This needs to be done after class index is chosen, for root metaclasses.
// This assumes that none of those classes have Swift contents,
// or that Swift's initializers have already been called.
// fixme that assumption will be wrong if we add support
// for ObjC subclasses of Swift classes.
// 递归调用,实现父类和元类
supercls = realizeClassWithoutSwift(remapClass(cls->superclass), nil);
metacls = realizeClassWithoutSwift(remapClass(cls->ISA()), nil);
#if SUPPORT_NONPOINTER_ISA
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.
// 禁用一些类和非指针isa
bool instancesRequireRawIsa = cls->instancesRequireRawIsa();
bool rawIsaIsInherited = false;
static bool hackedDispatch = false;
// 禁用非指针的 isa
if (DisableNonpointerIsa) {
// Non-pointer isa disabled by environment or app SDK version
// 非指针isa禁用的环境或应用程序SDK版本
instancesRequireRawIsa = true;
}
else if (!hackedDispatch && 0 == strcmp(ro->name, "OS_object"))
{
// 在 hackedDispatch 里 isa 也充当虚表指针
hackedDispatch = true;
instancesRequireRawIsa = true;
}
else if (supercls && supercls->superclass &&
supercls->instancesRequireRawIsa())
{
// 从元类到根元类设置
instancesRequireRawIsa = true;
rawIsaIsInherited = true;
}
if (instancesRequireRawIsa) {
cls->setInstancesRequireRawIsaRecursively(rawIsaIsInherited);
}
}
// SUPPORT_NONPOINTER_ISA
#endif
// 在重新映射时更新父类和元类
// Update superclass and metaclass in case of remapping
cls->superclass = supercls;
cls->initClassIsa(metacls);
// 协调实例变量的偏移量/布局,可能会重新分配 class_ro_t,更新我们的 ro 变量。
if (supercls && !isMeta) reconcileInstanceVariables(cls, supercls, ro);
// 如果还没有设置就开始设置 fastInstanceSize。
cls->setInstanceSize(ro->instanceSize);
// 将一些标志从 ro 复制到 rw
if (ro->flags & RO_HAS_CXX_STRUCTORS) {
cls->setHasCxxDtor();
if (! (ro->flags & RO_HAS_CXX_DTOR_ONLY)) {
cls->setHasCxxCtor();
}
}
// 从ro或父类中传播关联的对象禁止标志
if ((ro->flags & RO_FORBIDS_ASSOCIATED_OBJECTS) ||
(supercls && supercls->forbidsAssociatedObjects()))
{
rw->flags |= RW_FORBIDS_ASSOCIATED_OBJECTS;
}
// 将这个类连接到它的父类的子类列表,即双向绑定
if (supercls) {
addSubclass(supercls, cls);
} else {
addRootClass(cls);
}
// 整理 cls 的方法列表、协议列表和属性列表,以及附加任何未完成的类别
methodizeClass(cls, previously);
return cls;
}
- methodizeClass 分析
/***********************************************************************
* methodizeClass
* Fixes up cls's method list, protocol list, and property list.
* Attaches any outstanding categories.
* Locking: runtimeLock must be held by the caller
**********************************************************************/
//方法的序列化
static void methodizeClass(Class cls, Class previously)
{
runtimeLock.assertLocked();
bool isMeta = cls->isMetaClass();
auto rw = cls->data();
auto ro = rw->ro();
auto rwe = rw->ext();
// Methodizing for the first time
if (PrintConnecting) {
_objc_inform("CLASS: methodizing class '%s' %s",
cls->nameForLogging(), isMeta ? "(meta)" : "");
}
// Install methods and properties that the class implements itself.
// 将 ro 里面的方法附加到 rw 里面去
method_list_t *list = ro->baseMethods();
if (list) {
prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls));
if (rwe) rwe->methods.attachLists(&list, 1);
}
// 将 ro 里面的属性附加到 rw 里面去
property_list_t *proplist = ro->baseProperties;
if (rwe && proplist) {
rwe->properties.attachLists(&proplist, 1);
}
// 将 ro 里面的协议附加到 rw 里面去
protocol_list_t *protolist = ro->baseProtocols;
if (rwe && protolist) {
rwe->protocols.attachLists(&protolist, 1);
}
// Root classes get bonus method implementations if they don't have
// them already. These apply before category replacements.
// 根类获得额外的方法实现,如果它们还没有。这些适用于类别替换之前。
if (cls->isRootMetaclass()) {
// root metaclass
addMethod(cls, @selector(initialize), (IMP)&objc_noop_imp, "", NO);
}
// Attach categories. 附加分类
if (previously) {
if (isMeta) {
objc::unattachedCategories.attachToClass(cls, previously,
ATTACH_METACLASS);
} else {
// When a class relocates, categories with class methods
// may be registered on the class itself rather than on
// the metaclass. Tell attachToClass to look for those.
objc::unattachedCategories.attachToClass(cls, previously,
ATTACH_CLASS_AND_METACLASS);
}
}
objc::unattachedCategories.attachToClass(cls, cls,
isMeta ? ATTACH_METACLASS : ATTACH_CLASS);
#if DEBUG
// Debug: sanity-check all SELs; log method list contents
for (const auto& meth : rw->methods()) {
if (PrintConnecting) {
_objc_inform("METHOD %c[%s %s]", isMeta ? '+' : '-',
cls->nameForLogging(), sel_getName(meth.name));
}
ASSERT(sel_registerName(sel_getName(meth.name)) == meth.name);
}
#endif
}
- attachLists 分析
// 基本上方法、协议、属性都是通过 attachLists 函数附加到对应的列表上的
void attachLists(List* const * addedLists, uint32_t addedCount) {
if (addedCount == 0) return;
if (hasArray()) {
// many lists -> many lists
//计算数组中旧lists的大小
uint32_t oldCount = array()->count;
//计算新的容量大小 = 旧数据大小+新数据大小
uint32_t newCount = oldCount + addedCount;
//根据新的容量大小,开辟一个数组,类型是 array_t,通过array()获取
setArray((array_t *)realloc(array(), array_t::byteSize(newCount)));
//设置数组大小
array()->count = newCount;
//旧的数据从 addedCount 数组下标开始 存放旧的lists,大小为 旧数据大小 * 单个旧list大小
memmove(array()->lists + addedCount, array()->lists,
oldCount * sizeof(array()->lists[0]));
//新数据从数组 首位置开始存储,存放新的lists,大小为 新数据大小 * 单个list大小
memcpy(
array()->lists, addedLists,
addedCount * sizeof(array()->lists[0]));
}
else if (!list && addedCount == 1) {
// 0 lists -> 1 list
list = addedLists[0];//将list加入mlists的第一个元素,此时的list是一个一维数组
}
else {
// 1 list -> many lists 有了一个list,有往里加很多list
//新的list就是分类,来自LRU的算法思维,即最近最少使用
//获取旧的list
List* oldList = list;
uint32_t oldCount = oldList ? 1 : 0;
//计算容量和 = 旧list个数+新lists的个数
uint32_t newCount = oldCount + addedCount;
//开辟一个容量和大小的集合,类型是 array_t,即创建一个数组,放到array中,通过array()获取
setArray((array_t *)malloc(array_t::byteSize(newCount)));
//设置数组的大小
array()->count = newCount;
//判断old是否存在,old肯定是存在的,将旧的list放入到数组的末尾
if (oldList) array()->lists[addedCount] = oldList;
// memcpy(开始位置,放什么,放多大) 是内存平移,从数组起始位置存入新的list
//其中array()->lists 表示首位元素位置
memcpy(array()->lists, addedLists,
addedCount * sizeof(array()->lists[0]));
}
}