上篇文章我们探索了read_images
里面的几个比较重要的流程,这篇我们接着上篇文章剩下的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()) {
validateAlreadyRealizedClass(cls);
return cls;
}
ASSERT(cls == remapClass(cls));
// fixme verify class is not in an un-dlopened part of the shared cache?
//从mach-O中获取数据data,转换成class_ro_t
auto ro = (const class_ro_t *)cls->data();
auto isMeta = ro->flags & RO_META;
const char *mangledName = cls->nonlazyMangledName();
if (strcmp(mangledName, "LGPerson") == 0)
{
if (!isMeta) {
printf("%s LGPerson....\n",__func__);
}
}
//判断是否时元类
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的空间
rw = objc::zalloc<class_rw_t>();
//将ro赋值给rw
rw->set_ro(ro);
// flags:1 为当前类 2:元类
rw->flags = RW_REALIZED|RW_REALIZING|isMeta;
//给cls设置rw
cls->setData(rw);
}
cls->cache.initializeToEmptyOrPreoptimizedInDisguise();
#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->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->getSuperclass()), nil);
metacls = realizeClassWithoutSwift(remapClass(cls->ISA()), nil);
if (strcmp(mangledName, "LGPerson") == 0)
{
if (!isMeta) {
printf("%s LGPerson....\n",__func__);
}
}
#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->getName(), "OS_object"))
{
// hack for libdispatch et al - isa also acts as vtable pointer
hackedDispatch = true;
instancesRequireRawIsa = true;
}
else if (supercls && supercls->getSuperclass() &&
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->setSuperclass(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
methodizeClass(cls, previously);
return cls;
}
1.首先进行判断,判断类是否存在,如果不存在直接返回nil,然后在判断这个类是否已经验证实现,如果实现则返回当前类,只要时因为这个地方也存在递归实现元类与父类
,根类的父类为nil
、元类的isa指向自己
,所以这样可以保证类只会被初始化一次
if (!cls) return nil;
if (cls->isRealized()) {
validateAlreadyRealizedClass(cls);
return cls;
}
2.rw的初始化
- ro:
clean memory
,在编译期间确定的内存空间,只读不可改变,其存储着类名称、属性、协议、方法、实例变量
等 - rw:
dirty memory
,在 运行时 生成,可读可写,由于其动态性,可以往类中添加属性、方法、协议 - rwe :类的额外信息,只有不到10%的类真正的更改了他们的方法,并不是每一个类都需要插入数据,进行修改的类很少,避免资源的消耗,所以就有了rwe。rwe中存储的一般是
分类的信息、动态添加的方法
等
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 = cls->data();
ro = cls->data()->ro();
ASSERT(!isMeta);
cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);
} else {
// Normal class. Allocate writeable class data.
//开辟rw的空间
rw = objc::zalloc<class_rw_t>();
//将ro赋值给rw
rw->set_ro(ro);
// flags:1 为当前类 2:元类
rw->flags = RW_REALIZED|RW_REALIZING|isMeta;
//给cls设置rw
cls->setData(rw);
}
3.对类的父类和元类进行递归处理,是为了设置superClass
的继承链和isa
的走位图
//递归调用realizeClassWithoutSwift完善继承链,并处理当前类的父类、元类
//递归实现 设置当前类、父类、元类的 rw,主要目的是确定继承链 (类继承链、元类继承链)
//实现元类、父类
//当isa找到根元类之后,根元类的isa是指向自己的,不会返回nil从而导致死循环——remapClass中对类在表中进行查找的操作,如果表中已有该类,则返回一个空值;如果没有则返回当前类,这样保证了类只加载一次并结束递归
supercls = realizeClassWithoutSwift(remapClass(cls->superclass), nil);
metacls = realizeClassWithoutSwift(remapClass(cls->ISA()), nil);
...
// Update superclass and metaclass in case of remapping -- class 是 双向链表结构 即父子关系都确认了
// 将父类和元类给我们的类 分别是isa和父类的对应值
cls->superclass = supercls;
cls->initClassIsa(metacls);
...
// Connect this class to its superclass's subclass lists
//双向链表指向关系 父类中可以找到子类 子类中也可以找到父类
//通过addSubclass把当前类放到父类的子类列表中去
if (supercls) {
addSubclass(supercls, cls);
} else {
addRootClass(cls);
}
methodizeClass分析
static void methodizeClass(Class cls, Class previously)
{
runtimeLock.assertLocked();
bool isMeta = cls->isMetaClass();
const char *mangledName = cls->nonlazyMangledName();
if (strcmp(mangledName, "LGPerson") == 0)
{
if (!isMeta) {
printf("%s -LGPerson....\n",__func__);
}
}
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.
//将属性列表、方法列表、协议列表等贴到rwe中
// 将ro中的方法列表加入到rwe中
method_list_t *list = ro->baseMethods();
if (list) {
prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls), nullptr);
if (rwe) rwe->methods.attachLists(&list, 1);
}
//将属性添加到rwe中
property_list_t *proplist = ro->baseProperties;
if (rwe && proplist) {
rwe->properties.attachLists(&proplist, 1);
}
//将协议添加到rwe中
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 {
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
}
rwe的逻辑
方法列表
添加至rwe逻辑
- 获取ro的
baseMethods
- 通过
prepareMethodLists
方法排序 - 对
rwe
进行处理即通过attachLists
插入
方法排序 -prepareMethodLists
方法
static void
prepareMethodLists(Class cls, method_list_t **addedLists, int addedCount,
bool baseMethods, bool methodsFromBundle, const char *why)
{
...
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*/);
}
}
...
}
在prepareMethodLists
方法中 进行排序的主要方法fixupMethodList
为这个方法
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));
}
}
//排序
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();
}
}
接下来我们来验证一下这里是否是在进行方法的排序
image.png这里在排序之前实际上已经排好序了,主要是跟编译器有关,实在是整不出没有排好序的了。这里看下排序后的地址是由小到大进行排列的
总结:关于这部分的流程
_read_images
->relizeClassWithoutSwift(对于ro、rw的操作)
->methodizeClass
->prepareMethodLists
->fixupMethodList (主要是方法排序)
懒加载类与非懒加载类
非懒加载类
回到_read_images
方法,中的类的加载处理部分
// 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 = hi->nlclslist(&count);
for (i = 0; i < count; i++) {
Class cls = remapClass(classlist[i]);
if (!cls) continue;
const char *mangledName = cls->nonlazyMangledName();
if (strcmp(mangledName, "LGPerson") == 0)
{
printf("%s LGPerson....\n",__func__);
}
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);
}
}
- 我们将
LGPerson
中的load
方法去掉,再次运行程序,断点是不进入的 - 这里涉及到
懒加载类与非懒加载类
,如果有load
方法就会进行非懒加载
,程序启动的时候就会进行以上ro,rw,排序
等耗时操作
懒加载类
非懒加载类
即程序启动时便会加载,效率很低,所以苹果采用了按需加载
,也就是懒加载类
,等需要时再加载。
此时在main.m
中初始化我们的类
int main(int argc, const char * argv[]) {
@autoreleasepool {
// class_data_bits_t
LGPerson * person = [LGPerson alloc];
}
return 0;
}
在realizeClassWithoutSwift
方法中添加该类的断点
、
image.png此时
bt下查看函数调用栈
,发现了lookUpImpOrForward
函数,所以懒加载类
的加载是在消息的慢速查找流程中调用
网友评论