iOS--OC底层原理文章汇总
本文介绍类的信息加载。
前面篇章中简单分析了dyld的流程,再到dylibsystem调用_objc_init
,整个流程的目的是为了将类的信息加载到内存中。包括其属性、方法、协议、分类等,将代码编译,编成MachO
的格式,再写入到内存。
Mach-O为Mach object文件格式的缩写,它是mac以及iOS上一种用于可执行文件、目标代码、动态库的文件格式。常见:目标文件:
.o
;库文件.a
,.dylib
,Framework
;可执行文件:dyld
,.dsym
_read_images
先介绍读取镜像文件,它存在于objc工程中的objc-runtime-new.mm
中,代码量非常多,但我们从其中得到重要的信息,并对我们关心的类相关处理做分析。
1、条件控制进行的一次加载
2、修复预编译阶段的@selector的混乱问题
3、错误混乱的类处理
4、修复重映射一些没有被镜像文件加载进来的类
5、修复一些消息
6、当类里面有协议时:readProtocol 读取协议
7、修复没有被加载的协议
8、分类处理
9、类的加载处理
10、没有被处理的类,优化那些被侵犯的类
条件控制进行的一次加载
if (!doneOnce) {
// 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");
}
在doneOnce
流程中通过NXCreateMapTable
创建表,存放类信息,即创建一张类的哈希表gdb_objc_realized_classes
,其目的是为了类查找方便、快捷。
修复预编译阶段的@selector的混乱问题
从从 _getObjc2SelectorRefs获得MachO中的静态段__objc_selrefs,然后遍历获取sel,修复sel不一致问题。
// Fix up @selector references
static size_t UnfixedSelectors;
{
mutex_locker_t lock(selLock);
for (EACH_HEADER) {
if (hi->hasPreoptimizedSelectors()) continue;
bool isBundle = hi->isBundle();
//从 _getObjc2SelectorRefs获得MachO中的静态段__objc_selrefs
SEL *sels = _getObjc2SelectorRefs(hi, &count);
UnfixedSelectors += count;
// 对列表进行遍历
for (i = 0; i < count; i++) {
// 获取sel字符
const char *name = sel_cname(sels[i]);
// 透过name获取sel,该sel类型是:(SEL)*it.first,取了地址
SEL sel = sel_registerNameNoLock(name, isBundle);
// 如果名字可能相同,但地址不同,就修复不相同的的sel
if (sels[i] != sel) {
sels[i] = sel;
}
}
}
}
获取MachO中的静态段名
// 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");
错误混乱的类处理
// Discover classes. Fix up unresolved future classes. Mark bundle classes.
bool hasDyldRoots = dyld_shared_cache_some_image_overridden();
for (EACH_HEADER) {
if (! mustReadClasses(hi, hasDyldRoots)) {
// 如果镜像已经优化,无需调用readclass()
continue;
}
//获取编译后类列表中的所有类,从Mach-O获取__objc_classlist,获得一个classref_t类型的指针
classref_t const *classlist = _getObjc2ClassList(hi, &count);
bool headerIsBundle = hi->isBundle();
bool headerIsPreoptimized = hi->hasPreoptimizedClasses();
for (i = 0; i < count; i++) {
// 从列表中得到cls,但只有地址
Class cls = (Class)classlist[I];
// ** 读取类,使得cls获取的值有对应的name。此时cls包含了地址+类的name
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");
readClass读取类
cls
在readClass
被调用之前只是从表中获取到了地址,未获取name
/* 读取阅读类
* 读取由编译器编写的类和元类
* 返回新的类指针。这可能是:
* - cls
* - 零 (cls 缺少弱链接超类)
* - 其他内容(此类的空间由将来的类保留)
* 请注意,此功能执行的所有工作都由
* 必读类 () 。在不更新该函数之前,请勿更改
* 锁定:由用户或map_images获取的objc_readClassPair
*/
Class readClass(Class cls, bool headerIsBundle, bool headerIsPreoptimized)
{
// 若当前类没有父类,就返回nil
const char *mangledName = cls->mangledName();
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());
}
// 添加重映射的类
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());
}
// 读取newCls的data,从ro复制一份data,赋值给rw
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 {
// 添加缓存中的类信息
addNamedClass(cls, mangledName, replacing);
// 将处理后的cls插入到表中,即写到内存中
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;
}
补充:之前篇章中
objc_class
中有一个bits
->class_data_bits_t
,它下面有一个结构:
class_ro_t
(ro): read only 它是从存储中读取数据到内存中,用来存储name、方法、协议和实例变量等;加载完成后,改数据不会发生变化又称为干净内存(clean memory)
class_rw_t
(rw): read write 存储和获取。在进程运行时发生更改的内存。在数据增删改查过程中为了不对原来数据进行更改,为类在runtime过程中分配一个额外的内存,从ro中copy一份data到rw中,所以它是可变的。这个内存变成了脏内存(dirty memory)。但是在实际应用中,类的使用量只是10%,这样就在rw中造成了内存浪费,所以苹果就把rw中方法、协议和实例变量等放到了class_rw_ext_t中。
class_rw_ext_t
(rwe): read write ext,在runtime过程中存储类的方法、协议和实例变量等信息。
mangledName
获取cls的name
const char *mangledName() {
// fixme can't assert locks here
// ASSERT(this);
if (!this) {
return "";
}
if (isRealized() || isFuture()) {
// 判断如果已经初始化or将处理的,则就从ro中读取name
return data()->ro()->name;
} else {
// 从MachO的data中读取name
return ((const class_ro_t *)data())->name;
}
}
addNamedClass
将name、cls地址存储下来
/***********************************************************************
* addNamedClass
* Adds name => cls to the named non-meta class map. 将name=> cls添加到命名的非元类映射
* 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;
// 若dyld的共享缓存类中class有数据
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.
// 使用name查找,未按名称查找的类存在非元类表中
addNonMetaClass(cls);
} else {
//如果old类信息为nil,则将cls、name添加到gdb_objc_realized_classes哈希表存储。gdb_objc_realized_classes:不在dyld共享缓存中的命名类
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
将初始化之后的类存储到所有类的表中,如果有元类,会自动添加类的元类。
/***********************************************************************
* 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);
}
整个以上的过程为:从_read_images
,到类的处理readClass
,readClass
中,执行addNamedClass
,addClassTableEntry
,就将cls的地址、name就存储到了内存中。
类的加载处理
在类文件中比如LGPerson中实现
+load
{
// ...
}
在类处理是就可以直接进入以下代码:实现非懒加载类,
// Realize non-lazy classes (for +load methods and static instances)
for (EACH_HEADER) {
//通过_getObjc2NonlazyClassList获取Mach-O的静态段__objc_nlclslist非懒加载类表
classref_t const *classlist =
_getObjc2NonlazyClassList(hi, &count);
for (i = 0; i < count; i++) {
Class cls = remapClass(classlist[i]);
const char *mangledName = cls->mangledName();
const char *LGPersonName = "LGPerson";
if (strcmp(mangledName, LGPersonName) == 0) {
auto kc_ro = (const class_ro_t *)cls->data();
printf("_getObjc2NonlazyClassList: 这个是我要研究的 %s \n",LGPersonName);
}
//判断是否为空。不为空则就插入表。如果前面已经插入过了,则不会重新插入
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);
}
}
- 1.读取一个非懒加载
classlist
,对其进行遍历,如果该遍历的cls
已经存在表中,则继续。如果没有则添加到类表中。 - 2.
realizeClassWithoutSwift
实现遍历的当前类,加载出除cls地址、name之外的data数据。
realizeClassWithoutSwift->实现类
对类cls进行首次初始化,包括分配其读写数据,返回类的真实类结构。代码量挺多的就研究分析流程了。
该方法在分析消息流程的慢速查找流程时也出现过,判断类是否初始化,如果未初始化,则初始化cls,并最后实现类。
lookUpImpOrForward -> realizeClassMaybeSwiftAndLeaveLocked -> realizeClassMaybeSwiftMaybeRelock -> realizeClassWithoutSwift
OC底层原理08-objc_msgSend方法消息慢速查找(二)
- 1.读取MachO的data
将cls的data数据读取出来,并转换为class_ro_t *
,赋值给一个ro
.并且复制一份data给rw。
auto ro = (const class_ro_t *)cls->data();
auto isMeta = ro->flags & RO_META;
// 判断是否为未来才处理的类
if (ro->flags & RO_FUTURE) {
// This was a future class. rw data is already allocated. 分配rw
rw = cls->data();
ro = cls->data()->ro();
ASSERT(!isMeta);
cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);
} else {
// Normal class. Allocate writeable class data.正常类的情况就写入分配类data
// 开票一个空间给rw。
rw = objc::zalloc();
// 设置rw中ro
rw->set_ro(ro); //
rw->flags = RW_REALIZED|RW_REALIZING|isMeta;
cls->setData(rw); // 把rw的数据写入 :setData(rw) -> bits.setData(newData);
}
查看set_ro
的实现,可以发现set_ro -> set_ro_or_rwe
(找到 get_ro_or_rwe
,是通过ro_or_rw_ext_t
类型从ro_or_rw_ext
中获取) -> ro_or_rw_ext_t
中的ro
.如果有运行时,从rw中读取;反之,如果没有运行时,从ro
中读取.
- 2.确定集成链
递归调用realizeClassWithoutSwift,目的是为了本类的父类、元类的继承链,并实现了它们。
// 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);
// Connect this class to its superclass's subclass lists
//双向链表指向关系 父类中可以找到子类 子类中也可以找到父类
//通过addSubclass把当前类放到父类的子类列表中去
if (supercls) {
addSubclass(supercls, cls);
} else {
addRootClass(cls);
}
-
-
setInstancesRequireRawIsa
ormethodizeClass
-
#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.
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;
}
else if (!hackedDispatch && 0 == strcmp(ro->name, "OS_object"))
{
// hack for libdispatch et al - isa also acts as vtable pointer
hackedDispatch = true;
instancesRequireRawIsa = true;
}
else if (supercls && supercls->superclass &&
supercls->instancesRequireRawIsa())
{
// This is also propagated by addSubclass()
// but nonpointer isa setup needs it earlier.
// Special case: instancesRequireRawIsa does not propagate
// from root class to root metaclass
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);
// Reconcile instance variable offsets / layout.
// This may reallocate class_ro_t, updating our ro variable.
if (supercls && !isMeta) reconcileInstanceVariables(cls, supercls, ro);
// Set fastInstanceSize if it wasn't set already.
cls->setInstanceSize(ro->instanceSize);
// Copy some flags from ro to rw
if (ro->flags & RO_HAS_CXX_STRUCTORS) {
cls->setHasCxxDtor();
if (! (ro->flags & RO_HAS_CXX_DTOR_ONLY)) {
cls->setHasCxxCtor();
}
}
// Propagate the associated objects forbidden flag from ro or from
// the superclass.
if ((ro->flags & RO_FORBIDS_ASSOCIATED_OBJECTS) ||
(supercls && supercls->forbidsAssociatedObjects()))
{
rw->flags |= RW_FORBIDS_ASSOCIATED_OBJECTS;
}
// Connect this class to its superclass's subclass lists
if (supercls) {
addSubclass(supercls, cls);
} else {
addRootClass(cls);
}
// Attach categories 附加类别 将ro数据中方法列表(包括分类的方法)、属性列表、协议列表都写入到rw
methodizeClass(cls, previously);
return cls;
在main.m文件中调用一个类的初始化方法,在此处断点调试;首次进入该段代码,会先走cls->instancesRequireRawIsa();
流程,深入一下,就能找到
inline void
objc_object::initClassIsa(Class cls)
{
if (DisableNonpointerIsa || cls->instancesRequireRawIsa()) {
initIsa(cls, false/*not nonpointer*/, false);
} else {
initIsa(cls, true/*nonpointer*/, false);
}
}
就是一个初始化isa的必要条件。
我们在这里打印一下cls,能获取到cls
的信息。
(lldb) x/4gx cls
0x1000032e8: 0x00000001000032c0 0x0000000100335140
0x1000032f8: 0x000000010032f430 0x0000000000000000
// 依次是: isa ,继承,cache,bits
此时还未初始化,所以最后一个地址没有数据,是因为内存情况还未完善。但是如果这样(const class_ro_t *)cls->data();
是能获取到data数据的,通过指针是可以获取到数据的。
初始化空间,设置cls数据
// Set fastInstanceSize if it wasn't set already.
cls->setInstanceSize(ro->instanceSize);
// Copy some flags from ro to rw
if (ro->flags & RO_HAS_CXX_STRUCTORS) {
cls->setHasCxxDtor();
if (! (ro->flags & RO_HAS_CXX_DTOR_ONLY)) {
cls->setHasCxxCtor();
}
}
cls就有了初始值
(lldb) x/4gx cls
0x1000032e8: 0x00000001000032c0 0x0000000100335140
0x1000032f8: 0x000000010032f430 0x0000202400000000
根据数据流 : cls->data() -> ro -> rw ,rw数据里面的rwe是在methodizeClass中处理的。
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(); // rw中的ext 数据赋值给rwe
// 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.
method_list_t *list = ro->baseMethods(); // 获取方法列表
if (list) {
// 对方法列表进行排序
prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls));
if (rwe) rwe->methods.attachLists(&list, 1);
}
property_list_t *proplist = ro->baseProperties;
if (rwe && proplist) {
rwe->properties.attachLists(&proplist, 1);
}
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
}
- 在该方法中,进行了
ro、rw、rwe
初始赋值后。从ro
总读取到方法列表,将方法列表转换为method_list_t
类型的list
; - 对方法列表进行排序
prepareMethodLists
(属性、方法、协议表)。
static void
prepareMethodLists(Class cls, method_list_t **addedLists, int addedCount,
bool baseMethods, bool methodsFromBundle)
{
// ...
// Add method lists to array.
// Reallocate un-fixed method lists.
// The new methods are PREPENDED to the method list array.
for (int i = 0; i < addedCount; i++) {
method_list_t *mlist = addedLists[i];
ASSERT(mlist);
// Fixup selectors if necessary
if (!mlist->isFixedUp()) {
fixupMethodList(mlist, methodsFromBundle, true/*sort*/);//排序
}
}
// ...
}
// ----------------------
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.name = sel_registerNameNoLock(name, bundleCopy);
}
}
// Sort by selector address.根据sel地址排序
if (sort) {
method_t::SortBySELAddress sorter;
std::stable_sort(mlist->begin(), mlist->end(), sorter);
}
// Mark method list as uniqued and sorted
mlist->setFixedUp();
}
方法的排序原则是:根据sel地址排序
- 序列化各list之后,对rwe进行了赋值,此时rwe就有了值:
rwe->methods.attachLists
。
void attachToClass(Class cls, Class previously, int flags)
{
runtimeLock.assertLocked();
ASSERT((flags & ATTACH_CLASS) ||
(flags & ATTACH_METACLASS) ||
(flags & ATTACH_CLASS_AND_METACLASS));
const char *mangledName = cls->mangledName();
const char *LGPersonName = "LGPerson";
if (strcmp(mangledName, LGPersonName) == 0) {
bool kc_isMeta = cls->isMetaClass();
auto kc_rw = cls->data();
auto kc_ro = kc_rw->ro();
if (!kc_isMeta) {
printf("%s: 这个是我要研究的 %s \n",__func__,LGPersonName);
}
}
auto &map = get();
auto it = map.find(previously);//找到一个分类进来一次,即一个个加载分类,不要混乱
if (it != map.end()) {//这里会走进来:当主类没有实现load,分类开始加载,迫使主类加载,会走到if流程里面
category_list &list = it->second;
if (flags & ATTACH_CLASS_AND_METACLASS) {//判断是否是元类
int otherFlags = flags & ~ATTACH_CLASS_AND_METACLASS;
attachCategories(cls, list.array(), list.count(), otherFlags | ATTACH_CLASS);//实例方法
attachCategories(cls->ISA(), list.array(), list.count(), otherFlags | ATTACH_METACLASS);//类方法
} else {
//如果不是元类,则只走一次 attachCategories
attachCategories(cls, list.array(), list.count(), flags);
}
map.erase(it);
}
}
在 category_list
-> attachCategories
中有了对分类的操作处理,那么就需要对分类是如何加载再做一个探究—类加载(二)。
懒加载类&非懒加载类
区别:当前类是否实现load方法;不实现它就是懒加载,实现了+load
则是非懒加载。
1.懒加载类情况
把数据加载推迟到第一次消息
lookUpImpOrForward
realizeClassMaybeSwiftMaybeRelock
realizeClassWithoutSwift
methodizeClass
2.非懒加载类情况
实现load方法,在map_images
的时候,就加载所有类数据
_getObjc2NonlazyClassList
readClass
realizeClassWithoutSwift
methodizeClass
苹果方默认为了性能是采取懒加载类。