美文网首页
iOS学习相关内容

iOS学习相关内容

作者: MT_suny | 来源:发表于2020-07-08 14:21 被阅读0次

    OC基础_分类:

    分类的定义:分类是OC中的特有语法,它是表示一个指向分类结构体的指针,它是为了扩展系统类的方法而产生的一种方式。

    分类的作用:
    1.声明私有方法
    2.分解体积庞大的类方法
    3.把framework的私有方法公开

    分类的特点:1.运行时决议(在iOS中,当原有类的方法不够用时,这时候分类就出现了。Category是在现有类的基础上添加新的方法,利用Objective-C 的动态运行时分配机制,可以为现有类添加新方法。可以在分类中添加方法和成员变量,但是添加的成员变量不会自动生成settergetter方法,需要在实现部分给出实现。) 2.可以为系统类添加分类(不能给系统类添加扩展)

    分类中可以添加哪些内容:1.实例方法 2.类方法 3.协议 4.属性(实际只做声明,未实现settergetter方法.)

    struct objc_category {
        //分类名称
        char * _Nonnull category_name                            OBJC2_UNAVAILABLE; //unavailable in objc 2.0, deprecated in Leopard
        //宿主类
        char * _Nonnull class_name                               OBJC2_UNAVAILABLE;
        //实例方法列表
        struct objc_method_list * _Nullable instance_methods     OBJC2_UNAVAILABLE;
        //类方法类表
        struct objc_method_list * _Nullable class_methods        OBJC2_UNAVAILABLE;
        //协议列表
        struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
    }                                                            OBJC2_UNAVAILABLE;
    

    属性操作方式:例如我在分类.h文件中声明了一个可变数组

    @property (nonatomic,strong)NSMutableArray *dataArray;
    

    在.m文件中要实现

    //getter方法
    - (NSMutableArray *)dataArray{
        return objc_getAssociatedObject(self, "dataArray");
    }
    //setter方法
    - (void)setDataArray:(NSMutableArray *)dataArray{
        objc_setAssociatedObject(self, "dataArray", dataArray,OBJC_ASSOCIATION_RETAIN);
    }
    

    分类的加载调用栈:
    _objc_init->map_images->map_images_nolock->_read_images->methodizeClass

    _objc_init 方法的实现源码:

    void _objc_init(void)
    {
        static bool initialized = false;
        if (initialized) return;
        initialized = true;
        
        // fixme defer initialization until an objc-using image is found?
        environ_init();
        tls_init();
        static_init();
        runtime_init();
        exception_init();
        cache_init();
        _imp_implementationWithBlock_init();
     //方法注册了对dyld中关于加载images的事件回调(下面是原始方法)
     //void _dyld_objc_notify_register(_dyld_objc_notify_mapped mapped,_dyld_objc_notify_init init,_dyld_objc_notify_unmapped unmapped);
     //分别注册了那些事件呢?根据注释,我们可以知道,共注册了三个事件的回调:
        //_dyld_objc_notify_mapped : OC image被加载映射到内存(+load()方法在此时被调用)
        //_dyld_objc_notify_init : OC image被init时
        //_dyld_objc_notify_unmapped : OC image被移除内存时
        _dyld_objc_notify_register(&map_images, load_images, unmap_image);
    #if __OBJC2__
        didCallDyldNotifyRegister = true;
    #endif
    }
    

    当image被dyld加载到内存后,会调用回调_dyld_objc_notify_mapped 。在runtime中,对应的函数是map_images下面是源码:

    void map_images(unsigned count, const char * const paths[],
               const struct mach_header * const mhdrs[])
    {
        mutex_locker_t lock(runtimeLock);
       // map_images方法实质上会调用map_images_nolock方法。
       // 而在map_images_nolock内部,又调用了_read_images方法,
       // 其核心是用来读取Mach-O格式文件的runtime相关的section信息,
       // 并转化为runtime内部的数据结构
        return map_images_nolock(count, paths, mhdrs);
    }
    

    map_images_nolock方法下面是源码:

    void 
    map_images_nolock(unsigned mhCount, const char * const mhPaths[],
                      const struct mach_header * const mhdrs[])
    {
        static bool firstTime = YES;
        header_info *hList[mhCount];
        uint32_t hCount;
        size_t selrefCount = 0;
    
        // Perform first-time initialization if necessary.
        // This function is called before ordinary library initializers. 
        // fixme defer initialization until an objc-using image is found?
        if (firstTime) {
            preopt_init();
        }
    
        if (PrintImages) {
            _objc_inform("IMAGES: processing %u newly-mapped images...\n", mhCount);
        }
    
    
        // Find all images with Objective-C metadata.
        hCount = 0;
    
        // Count classes. Size various table based on the total.
        int totalClasses = 0;
        int unoptimizedTotalClasses = 0;
        {
            uint32_t i = mhCount;
            while (i--) {
                const headerType *mhdr = (const headerType *)mhdrs[i];
    
                auto hi = addHeader(mhdr, mhPaths[i], totalClasses, unoptimizedTotalClasses);
                if (!hi) {
                    // no objc data in this entry
                    continue;
                }
                
                if (mhdr->filetype == MH_EXECUTE) {
                    // Size some data structures based on main executable's size
    #if __OBJC2__
                    size_t count;
                    _getObjc2SelectorRefs(hi, &count);
                    selrefCount += count;
                    _getObjc2MessageRefs(hi, &count);
                    selrefCount += count;
    #else
                    _getObjcSelectorRefs(hi, &selrefCount);
    #endif
                    
    #if SUPPORT_GC_COMPAT
                    // Halt if this is a GC app.
                    if (shouldRejectGCApp(hi)) {
                        _objc_fatal_with_reason
                            (OBJC_EXIT_REASON_GC_NOT_SUPPORTED, 
                             OS_REASON_FLAG_CONSISTENT_FAILURE, 
                             "Objective-C garbage collection " 
                             "is no longer supported.");
                    }
    #endif
                }
                
                hList[hCount++] = hi;
                
                if (PrintImages) {
                    _objc_inform("IMAGES: loading image for %s%s%s%s%s\n", 
                                 hi->fname(),
                                 mhdr->filetype == MH_BUNDLE ? " (bundle)" : "",
                                 hi->info()->isReplacement() ? " (replacement)" : "",
                                 hi->info()->hasCategoryClassProperties() ? " (has class properties)" : "",
                                 hi->info()->optimizedByDyld()?" (preoptimized)":"");
                }
            }
        }
    
        // Perform one-time runtime initialization that must be deferred until 
        // the executable itself is found. This needs to be done before 
        // further initialization.
        // (The executable may not be present in this infoList if the 
        // executable does not contain Objective-C code but Objective-C 
        // is dynamically loaded later.
        if (firstTime) {
            sel_init(selrefCount);
            arr_init();
    
    #if SUPPORT_GC_COMPAT
            // Reject any GC images linked to the main executable.
            // We already rejected the app itself above.
            // Images loaded after launch will be rejected by dyld.
    
            for (uint32_t i = 0; i < hCount; i++) {
                auto hi = hList[i];
                auto mh = hi->mhdr();
                if (mh->filetype != MH_EXECUTE  &&  shouldRejectGCImage(mh)) {
                    _objc_fatal_with_reason
                        (OBJC_EXIT_REASON_GC_NOT_SUPPORTED, 
                         OS_REASON_FLAG_CONSISTENT_FAILURE, 
                         "%s requires Objective-C garbage collection "
                         "which is no longer supported.", hi->fname());
                }
            }
    #endif
    
    #if TARGET_OS_OSX
            // Disable +initialize fork safety if the app is too old (< 10.13).
            // Disable +initialize fork safety if the app has a
            //   __DATA,__objc_fork_ok section.
    
            if (dyld_get_program_sdk_version() < DYLD_MACOSX_VERSION_10_13) {
                DisableInitializeForkSafety = true;
                if (PrintInitializing) {
                    _objc_inform("INITIALIZE: disabling +initialize fork "
                                 "safety enforcement because the app is "
                                 "too old (SDK version " SDK_FORMAT ")",
                                 FORMAT_SDK(dyld_get_program_sdk_version()));
                }
            }
    
            for (uint32_t i = 0; i < hCount; i++) {
                auto hi = hList[i];
                auto mh = hi->mhdr();
                if (mh->filetype != MH_EXECUTE) continue;
                unsigned long size;
                if (getsectiondata(hi->mhdr(), "__DATA", "__objc_fork_ok", &size)) {
                    DisableInitializeForkSafety = true;
                    if (PrintInitializing) {
                        _objc_inform("INITIALIZE: disabling +initialize fork "
                                     "safety enforcement because the app has "
                                     "a __DATA,__objc_fork_ok section");
                    }
                }
                break;  // assume only one MH_EXECUTE image
            }
    #endif
    
        }
    //这里是核心代码区
        if (hCount > 0) {
            _read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
        }
    
        firstTime = NO;
        
        // Call image load funcs after everything is set up.
        for (auto func : loadImageFuncs) {
            for (uint32_t i = 0; i < mhCount; i++) {
                func(mhdrs[i]);
            }
        }
    }
    

    methodizeClass的方法实现源码:

    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();
    
        // 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
    }
    

    相关文章

      网友评论

          本文标题:iOS学习相关内容

          本文链接:https://www.haomeiwen.com/subject/zqgifktx.html