iOS 类的加载分析 (中)

简介: 我们都知道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<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 : 类别, 分类


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


extension : 类扩展


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




目录
相关文章
|
2月前
|
搜索推荐 Android开发 iOS开发
安卓与iOS系统的用户界面设计对比分析
本文通过对安卓和iOS两大操作系统的用户界面设计进行对比分析,探讨它们在设计理念、交互方式、视觉风格等方面的差异及各自特点,旨在帮助读者更好地理解和评估不同系统的用户体验。
27 1
|
3月前
|
Android开发 数据安全/隐私保护 iOS开发
安卓与iOS系统的发展趋势与比较分析
【2月更文挑战第6天】 在移动互联网时代,安卓和iOS系统作为两大主流移动操作系统,各自呈现出不同的发展趋势。本文将从技术角度出发,对安卓和iOS系统的发展方向、特点及未来趋势进行比较分析,以期为读者提供更深入的了解和思考。
38 4
|
8月前
|
C语言 索引
09-iOS之load和initialize底层调用原理分析
09-iOS之load和initialize底层调用原理分析
58 0
|
3月前
|
安全 搜索推荐 Android开发
Android 与 iOS 的比较分析
【2月更文挑战第5天】 Android 和 iOS 是目前市场上两种最流行的移动操作系统,它们都拥有自己的特点和优势。本文将会分别从操作系统设计、应用生态、安全性等方面对这两种操作系统进行比较和分析,希望能够帮助读者更好地选择适合自己的移动设备。
|
7月前
|
iOS开发 MacOS
iOS指定加载任意语言
iOS指定加载任意语言
47 2
|
人工智能 文字识别 API
iOS MachineLearning 系列(4)—— 静态图像分析之物体识别与分类
本系列的前几篇文件,详细了介绍了Vision框架中关于静态图片区域识别的内容。本篇文章,我们将着重介绍静态图片中物体的识别与分类。物体识别和分类也是Machine Learning领域重要的应用。通过大量的图片数据进行训练后,模型可以轻易的分析出图片的属性以及图片中物体的属性。
239 0
|
算法 API iOS开发
iOS MachineLearning 系列(3)—— 静态图像分析之区域识别
本系列的前一篇文章介绍了如何使用iOS中自带的API对图片中的矩形区域进行分析。在图像静态分析方面,矩形区域分析是非常基础的部分。API还提供了更多面向应用的分析能力,如文本区域分析,条形码二维码的分析,人脸区域分析,人体分析等。本篇文章主要介绍这些分析API的应用。
219 0
|
10月前
|
存储 编解码 缓存
HTTP Live Streaming直播(iOS直播)技术分析与实现
HTTP Live Streaming直播(iOS直播)技术分析与实现
135 1
|
12月前
|
自然语言处理 搜索推荐 iOS开发
iOS MachineLearning 系列(19)—— 分析文本中的问题答案
本篇文章将介绍Apple官方推荐的唯一的一个文本处理模型:BERT-SQuAD。此模型用来分析一段文本,并根据提供的问题在文本中寻找答案。需要注意,BERT模型不会生成新的句子,它会从提供的文本中找到最有可能的答案段落或句子。
137 0
iOS MachineLearning 系列(19)—— 分析文本中的问题答案
|
12月前
|
监控 iOS开发 MacOS
iOS 友盟崩溃日志分析——Binary images
iOS 友盟崩溃日志分析——Binary images
214 0