iOS 类的加载分析 (中)

非懒加载类和懒加载类

总纲领: 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();  
        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 : 类别, 分类

  1. 专门用来给类添加新的方法
  2. 不能给类添加属性, 添加了成员变量, 也无法取到 (具体要看分类的结构)
  3. 注意: 其实可以通过runtime给分类添加属性
  4. 分类中用@property定义变量, 只会生成getter, setter方法的声明, 不能生成方法实现和带下划线的成员变量.

extension : 类扩展

  1. 可以说是特殊的分类, 也称作匿名分类
  2. 可以给类添加变量属性, 但是是私有变量
  3. 可以给类添加方法, 也是私有方法.

你可能感兴趣的:(iOS 类的加载分析 (中))