Runtime

作者: 今晚打老虎_9527 | 来源:发表于2018-08-06 15:31 被阅读0次

    oc对象

    OC类对象元类对象编译后的结构如下结构体

    struct objc_class : objc_object {
        // Class ISA;
        Class superclass;
        cache_t cache;             // formerly cache pointer and vtable
        class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
    
        class_rw_t *data() { 
            return bits.data();
        }
    }
    
    struct objc_object {
    private:
        isa_t isa;
    };
    
    

    isa

    • arm64架构之前isa只是一个指针,指向类对象或者元类对象
    • arm64架构之后isa是一个共用体
    union isa_t 
    {
        isa_t() { }
        isa_t(uintptr_t value) : bits(value) { }
    
        Class cls;
        uintptr_t bits;
    
    # if __arm64__
    #   define ISA_MASK        0x0000000ffffffff8ULL
    #   define ISA_MAGIC_MASK  0x000003f000000001ULL
    #   define ISA_MAGIC_VALUE 0x000001a000000001ULL
        struct {
            uintptr_t nonpointer        : 1;  //是否非指针  
            uintptr_t has_assoc         : 1;  //是否有关联对象
            uintptr_t has_cxx_dtor      : 1;  //是否有c++析构函数
            uintptr_t shiftcls          : 33; // MACH_VM_MAX_ADDRESS 0x1000000000   //类对象/元类对象地址
            uintptr_t magic             : 6;  //调试时对象是否完成初始化
            uintptr_t weakly_referenced : 1; //是否被弱指针引用过
            uintptr_t deallocating      : 1;  //是否正在释放
            uintptr_t has_sidetable_rc  : 1; //该值为1时表示对象引用计数过大,无法存在isa中,存在SideTable的属性中
            uintptr_t extra_rc          : 19; //存放对象引用计数的-1值
    #       define RC_ONE   (1ULL<<45)
    #       define RC_HALF  (1ULL<<18)
        };
    
    
    

    cache

    方法缓存

    struct cache_t {
        struct bucket_t *_buckets;  //散列表
        mask_t _mask;    //散列表方法-1
        mask_t _occupied;   //已经缓存的方法数
    }
    
    • 散列表(Hash table,也叫哈希表)
      缓存方法的时候,用@selector(method) & _mask 得到索引,以@selector(method) 为key,以函数地址为值,存到散列表中,取的时候用@selector(method) & _mask 得到索引,直接用索引取函数地址
    struct bucket_t {
    private:
        cache_key_t _key;
        IMP _imp;
    public:
        inline cache_key_t key() const { return _key; }
        inline IMP imp() const { return (IMP)_imp; }
        inline void setKey(cache_key_t newKey) { _key = newKey; }
        inline void setImp(IMP newImp) { _imp = newImp; }
    
        void set(cache_key_t newKey, IMP newImp);
    }
    

    oc方法调用

    消息机制:给方法调用者发送消息

    • oc的方法调用,其实都是转换为objc_msgSend函数的调用
    • objc_msgSend的执行流程分为3个阶段
      • 消息发送
      • 动态方法解析
      • 消息转发
    objc_msgSend()关键代码
    /***********************************************************************
    * lookUpImpOrForward.
    * The standard IMP lookup. 
    * initialize==NO tries to avoid +initialize (but sometimes fails)
    * cache==NO skips optimistic unlocked lookup (but uses cache elsewhere)
    * Most callers should use initialize==YES and cache==YES.
    * inst is an instance of cls or a subclass thereof, or nil if none is known. 
    *   If cls is an un-initialized metaclass then a non-nil inst is faster.
    * May return _objc_msgForward_impcache. IMPs destined for external use 
    *   must be converted to _objc_msgForward or _objc_msgForward_stret.
    *   If you don't want forwarding at all, use lookUpImpOrNil() instead.
    **********************************************************************/
    IMP lookUpImpOrForward(Class cls, SEL sel, id inst, 
                           bool initialize, bool cache, bool resolver)
    {
        IMP imp = nil;
        bool triedResolver = NO;
    
        runtimeLock.assertUnlocked();
    
        // Optimistic cache lookup
        if (cache) {
            imp = cache_getImp(cls, sel);
            if (imp) return imp;
        }
    
        // runtimeLock is held during isRealized and isInitialized checking
        // to prevent races against concurrent realization.
    
        // runtimeLock is held during method search to make
        // method-lookup + cache-fill atomic with respect to method addition.
        // Otherwise, a category could be added but ignored indefinitely because
        // the cache was re-filled with the old value after the cache flush on
        // behalf of the category.
    
        runtimeLock.read();
    
        if (!cls->isRealized()) {
            // Drop the read-lock and acquire the write-lock.
            // realizeClass() checks isRealized() again to prevent
            // a race while the lock is down.
            runtimeLock.unlockRead();
            runtimeLock.write();
    
            realizeClass(cls);
    
            runtimeLock.unlockWrite();
            runtimeLock.read();
        }
    
        if (initialize  &&  !cls->isInitialized()) {
            runtimeLock.unlockRead();
            _class_initialize (_class_getNonMetaClass(cls, inst));
            runtimeLock.read();
            // If sel == initialize, _class_initialize will send +initialize and 
            // then the messenger will send +initialize again after this 
            // procedure finishes. Of course, if this is not being called 
            // from the messenger then it won't happen. 2778172
        }
    
        
     retry:    
        runtimeLock.assertReading();
    
        // Try this class's cache.
    
        imp = cache_getImp(cls, sel);
        if (imp) goto done;
    
        // Try this class's method lists.
        {
            Method meth = getMethodNoSuper_nolock(cls, sel);
            if (meth) {
                log_and_fill_cache(cls, meth->imp, sel, inst, cls);
                imp = meth->imp;
                goto done;
            }
        }
    
        // Try superclass caches and method lists.
        {
            unsigned attempts = unreasonableClassCount();
            for (Class curClass = cls->superclass;
                 curClass != nil;
                 curClass = curClass->superclass)
            {
                // Halt if there is a cycle in the superclass chain.
                if (--attempts == 0) {
                    _objc_fatal("Memory corruption in class list.");
                }
                
                // Superclass cache.
                imp = cache_getImp(curClass, sel);
                if (imp) {
                    if (imp != (IMP)_objc_msgForward_impcache) {
                        // Found the method in a superclass. Cache it in this class.
                        log_and_fill_cache(cls, imp, sel, inst, curClass);
                        goto done;
                    }
                    else {
                        // Found a forward:: entry in a superclass.
                        // Stop searching, but don't cache yet; call method 
                        // resolver for this class first.
                        break;
                    }
                }
                
                // Superclass method list.
                Method meth = getMethodNoSuper_nolock(curClass, sel);
                if (meth) {
                    log_and_fill_cache(cls, meth->imp, sel, inst, curClass);
                    imp = meth->imp;
                    goto done;
                }
            }
        }
    
        // No implementation found. Try method resolver once.
    
        if (resolver  &&  !triedResolver) {
            runtimeLock.unlockRead();
            _class_resolveMethod(cls, sel, inst);
            runtimeLock.read();
            // Don't cache the result; we don't hold the lock so it may have 
            // changed already. Re-do the search from scratch instead.
            triedResolver = YES;
            goto retry;
        }
    
        // No implementation found, and method resolver didn't help. 
        // Use forwarding.
    
        imp = (IMP)_objc_msgForward_impcache;
        cache_fill(cls, sel, imp, inst);
    
     done:
        runtimeLock.unlockRead();
    
        return imp;
    }
    
    
    动态方法解析
    //  Person.h
    //  8-Runtime
    //
    //  Created by 今晚打老虎 on 2018/8/6.
    //  Copyright © 2018年 今晚打老虎. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @interface Person : NSObject
    
    - (void)test;
    
    @end
    
    //  Person.m
    //  8-Runtime
    //
    //  Created by 今晚打老虎 on 2018/8/6.
    //  Copyright © 2018年 今晚打老虎. All rights reserved.
    //
    
    #import "Person.h"
    #import <objc/runtime.h>
    
    @implementation Person
    
    - (void)other{
        NSLog(@"%s", __func__);
    }
    
    + (BOOL)resolveInstanceMethod:(SEL)sel{
        
        if (sel == @selector(test)) {
            
            Method method = class_getInstanceMethod(self, @selector(other));
            
            class_addMethod(self, sel, method_getImplementation(method), method_getTypeEncoding(method));
            
            return YES;
        }
        
        return [super resolveInstanceMethod:sel];
        
    }
    
    @end
    

    API-类相关

    动态创建一个类(参数:父类,类名,额外的内存空间)
    Class objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes)

    注册一个类(要在类注册之前添加成员变量)
    void objc_registerClassPair(Class cls)

    销毁一个类
    void objc_disposeClassPair(Class cls)

    获取isa指向的Class
    Class object_getClass(id obj)

    设置isa指向的Class
    Class object_setClass(id obj, Class cls)

    判断一个OC对象是否为Class
    BOOL object_isClass(id obj)

    判断一个Class是否为元类
    BOOL class_isMetaClass(Class cls)

    获取父类
    Class class_getSuperclass(Class cls)

    API-成员变量

    获取一个实例变量信息
    Ivar class_getInstanceVariable(Class cls, const char *name)

    拷贝实例变量列表(最后需要调用free释放)
    Ivar *class_copyIvarList(Class cls, unsigned int *outCount)

    设置和获取成员变量的值
    void object_setIvar(id obj, Ivar ivar, id value)
    id object_getIvar(id obj, Ivar ivar)

    动态添加成员变量(已经注册的类是不能动态添加成员变量的)
    BOOL class_addIvar(Class cls, const char * name, size_t size, uint8_t alignment, const char * types)

    获取成员变量的相关信息
    const char *ivar_getName(Ivar v)
    const char *ivar_getTypeEncoding(Ivar v)

    API-属性

    获取一个属性
    objc_property_t class_getProperty(Class cls, const char *name)

    拷贝属性列表(最后需要调用free释放)
    objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)

    动态添加属性
    BOOL class_addProperty(Class cls, const char *name, const objc_property_attribute_t *attributes,
    unsigned int attributeCount)

    动态替换属性
    void class_replaceProperty(Class cls, const char *name, const objc_property_attribute_t *attributes,
    unsigned int attributeCount)

    获取属性的一些信息
    const char *property_getName(objc_property_t property)
    const char *property_getAttributes(objc_property_t property)

    API-方法

    获得一个实例方法、类方法
    Method class_getInstanceMethod(Class cls, SEL name)
    Method class_getClassMethod(Class cls, SEL name)

    方法实现相关操作
    IMP class_getMethodImplementation(Class cls, SEL name)
    IMP method_setImplementation(Method m, IMP imp)
    void method_exchangeImplementations(Method m1, Method m2)

    拷贝方法列表(最后需要调用free释放)
    Method *class_copyMethodList(Class cls, unsigned int *outCount)

    动态添加方法
    BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)

    动态替换方法
    IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)

    获取方法的相关信息(带有copy的需要调用free去释放)
    SEL method_getName(Method m)
    IMP method_getImplementation(Method m)
    const char *method_getTypeEncoding(Method m)
    unsigned int method_getNumberOfArguments(Method m)
    char *method_copyReturnType(Method m)
    char *method_copyArgumentType(Method m, unsigned int index)

    选择器相关
    const char *sel_getName(SEL sel)
    SEL sel_registerName(const char *str)

    用block作为方法实现
    IMP imp_implementationWithBlock(id block)
    id imp_getBlock(IMP anImp)
    BOOL imp_removeBlock(IMP anImp)

    相关文章

      网友评论

          本文标题:Runtime

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