非懒加载类和懒加载类
总纲领: OC底层探寻
上篇: iOS dyld与objc的关联
我们都知道iOS的整体机制是懒加载, 也是就是使用到, 再去加载, 不使用就释放掉来节省内存.
1. 懒加载类
懒加载类, 他的数据加载是推迟到第一次消息的时候:
数据执行的顺序为 lookUpImpForward
-> realizeClassMayBeSwifeMayBeRelock
-> realizeClassWithoutSwife
-> methodizeClass
2. 非懒加载类
map_images
的时候, 加载所有数据. (例如: 可以在类中增加 +load()
方法, 来将该类变为非懒加载类, 并且我们知道类中load方法在main函数之前调用)
数据执行的顺序为 _getObjc2NonlazyClassList
-> readClass
-> realizeClassWithoutSwife
-> methodizeClass
_read_images
以下是_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) - 懒加载类 -> 非懒加载类 // 懒 别人不懂我 我就不动 - 让它 提前加载 - load_images 类 // 懒加载类在什么时候? for (EACH_HEADER) { 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 } // alloc init - 类存在 完备 实例 realizeClassWithoutSwift(cls, nil); } }
以下是realizeClassWithoutSwift
源码, 具体解析请看代码中注释:
/*********************************************************************** * realizeClassWithoutSwift * Performs first-time initialization on class cls, * including allocating its read-write data. * Does not perform any Swift-side initialization. * Returns the real class structure for the class. * Locking: runtimeLock must be write-locked by the caller **********************************************************************/ static Class realizeClassWithoutSwift(Class cls, Class previously) { runtimeLock.assertLocked(); class_rw_t *rw; Class supercls; Class metacls; const char *mangledName = cls->mangledName(); const char *LGPersonName = "LGPerson"; //对研究对象进行过滤 (针对自己写的自定义类进行研究) if (strcmp(mangledName, LGPersonName) == 0) { auto kc_ro = (const class_ro_t *)cls->data(); auto kc_isMeta = kc_ro->flags & RO_META; if (!kc_isMeta) { printf("%s: 这个是我要研究的 %s \n",__func__,LGPersonName); } } if (!cls) return nil; if (cls->isRealized()) return cls; ASSERT(cls == remapClass(cls)); // fixme verify class is not in an un-dlopened part of the shared cache? / ro (read only) rw (read write) rwe (read write ext) rwe只在该类有分类时才有意义 // data() -> ro 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 = objc::zalloc<class_rw_t>(); rw->set_ro(ro); rw->flags = RW_REALIZED|RW_REALIZING|isMeta; cls->setData(rw); } #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. // cls 信息 -> 父类 -> 元类 : cls LGPerson 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. 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 - 分类 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 **********************************************************************/ // realizeClassWithoutSwift 尽管看到了 data() -> ro -> rw (rwe) // ro - methodlist - 方法查找的时候 (二分查找) sel 排序 (以下代码为类加载的时候, 就对methedlist进行了排序, 这也就解释了为什么可以用二分查找) 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(); 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); } } // 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(); // 如果有list, 则对list进行排序 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 }
类扩展VS分类
category
: 类别, 分类
- 专门用来给类添加新的方法
- 不能给类添加属性, 添加了成员变量, 也无法取到 (具体要看分类的结构)
- 注意: 其实可以通过runtime给分类添加属性
- 分类中用@property定义变量, 只会生成getter, setter方法的声明, 不能生成方法实现和带下划线的成员变量.
extension
: 类扩展
- 可以说是特殊的分类, 也称作匿名分类
- 可以给类添加变量属性, 但是是私有变量
- 可以给类添加方法, 也是私有方法.