美文网首页
oc常用方法底层实现分析

oc常用方法底层实现分析

作者: 浪的出名 | 来源:发表于2020-09-15 17:28 被阅读0次

    class_getInstanceMethod和class_getClassMethod

    • class_getInstanceMethod的源码实现如下
    Method class_getInstanceMethod(Class cls, SEL sel)
    {
        if (!cls  ||  !sel) return nil;
    
        // This deliberately avoids +initialize because it historically did so.
    
        // This implementation is a bit weird because it's the only place that 
        // wants a Method instead of an IMP.
    
    #warning fixme build and search caches
            
        // Search method lists, try method resolver, etc.
        lookUpImpOrForward(nil, sel, cls, LOOKUP_RESOLVER);
    
    #warning fixme build and search caches
    
        return _class_getMethod(cls, sel);
    }
    
    • 查找方法流程图如下


      image.png
    • search_method_list_inline内部会对排序过的方法列表二分查找,没排序的遍历查找
    ALWAYS_INLINE static method_t *
    search_method_list_inline(const method_list_t *mlist, SEL sel)
    {
        int methodListIsFixedUp = mlist->isFixedUp();
        int methodListHasExpectedSize = mlist->entsize() == sizeof(method_t);
        
        if (fastpath(methodListIsFixedUp && methodListHasExpectedSize)) {//如果是排序过的方法列表使用2分查找
            return findMethodInSortedMethodList(sel, mlist);
        } else {
            // Linear search of unsorted method list
            for (auto& meth : *mlist) {// 遍历查找
                if (meth.name == sel) return &meth;
            }
        }
    
    #if DEBUG
        // sanity-check negative results
        if (mlist->isFixedUp()) {
            for (auto& meth : *mlist) {
                if (meth.name == sel) {
                    _objc_fatal("linear search worked when binary search did not");
                }
            }
        }
    #endif
    
        return nil;
    }
    
    • class_getClassMethod的源码实现
    Method class_getClassMethod(Class cls, SEL sel)
    {
        if (!cls  ||  !sel) return nil;
    
        return class_getInstanceMethod(cls->getMeta(), sel);
    }
    
    Class getMeta() {// 如果是元类返回自身,不是元类放回自身的isa也就是元类
            if (isMetaClass()) return (Class)this;
            else return this->ISA();
        }
    
    • class_getInstanceMethod会从其类对象及其父类的方法列表中查找,class_getClassMethod会从元类对象及其元类父类的方法列表中查找方法。实例方法和类方法在类对象和元类对象中存储的形式是一样的。
    • 通过一个例子来理解下上述的结论,新建一个Person类
    @interface Person : NSObject
    - (void)sayHello;
    + (void)say666;
    @end
    
    @implementation Person
    - (void)sayHello{
        NSLog(@"%s",__func__);
    }
    + (void) say666{
        NSLog(@"%s",__func__);
    }
    @end
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            Person *p = [[Person alloc] init];
            Class pClass     = object_getClass(p);
            const char *className = class_getName(pClass);
            Class metaClass = objc_getMetaClass(className);
            
            Method method1 = class_getInstanceMethod(pClass, @selector(sayHello));
            Method method2 = class_getInstanceMethod(metaClass, @selector(sayHello));
            Method method3 = class_getInstanceMethod(pClass, @selector(say666));
            Method method4 = class_getInstanceMethod(metaClass, @selector(say666));
            
            Method method5 = class_getClassMethod(pClass, @selector(sayHello));
            Method method6 = class_getClassMethod(metaClass, @selector(sayHello));
            Method method7 = class_getClassMethod(pClass, @selector(say666));
            Method method8 = class_getClassMethod(metaClass, @selector(say666));
            
            NSLog(@"%p-%p-%p-%p",method1,method2,method3,method4);
            NSLog(@"%p-%p-%p-%p",method5,method6,method7,method8);
        }
        return 0;
    }
    
    • 上述代码打印结果为
    2020-09-15 16:12:41.727544+0800 class_getMethod[3431:20892761] 0x1000020c0-0x0-0x0-0x100002058
    2020-09-15 16:12:41.728234+0800 class_getMethod[3431:20892761] 0x0-0x0-0x100002058-0x100002058
    

    isKindOfClass和isMemberOfClass

    • 我们看看下面这段代码的打印结果
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            // insert code here...
            BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];      
            BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];     
            BOOL re3 = [(id)[Person class] isKindOfClass:[Person class]];       
            BOOL re4 = [(id)[Person class] isMemberOfClass:[Person class]];     
    
            BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];       
            BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];     
            BOOL re7 = [(id)[Person alloc] isKindOfClass:[Person class]];       
            BOOL re8 = [(id)[Person alloc] isMemberOfClass:[Person class]];     
            NSLog(@"%d-%d-%d-%d",re1,re2,re3,re4);
            NSLog(@"%d-%d-%d-%d",re5,re6,re7,re8);
        }
        return 0;
    }
    // 打印结果
    2020-09-15 16:31:20.515562+0800 KCObjc[4756:20941428] 1-0-0-0
    2020-09-15 16:31:20.516222+0800 KCObjc[4756:20941428] 1-1-1-1
    
    • 直接查看isKindOfClass和isMemberOfClass的源码
    + (BOOL)isKindOfClass:(Class)cls {//调用class的元类或元类的父类是否等于cls
        for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {
            if (tcls == cls) return YES;
        }
        return NO;
    }
    - (BOOL)isKindOfClass:(Class)cls {//调用对象的class或父类是否等于cls
        for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
            if (tcls == cls) return YES;
        }
        return NO;
    }
    ------------------------------------------------------------------------------------------
    + (BOOL)isMemberOfClass:(Class)cls {//调用class的元类是否等于cls
        return self->ISA() == cls;
    }
    
    - (BOOL)isMemberOfClass:(Class)cls {//调用对象的class是否等于cls
        return [self class] == cls;
    }
    
    • 通过源码调试发现外部调用isKindOfClass并不是走的上述的实现,而是走的objc_opt_isKindOfClass,应该是llvm编译器作了处理。
    // Calls [obj isKindOfClass]
    BOOL
    objc_opt_isKindOfClass(id obj, Class otherClass)//id表示调用者,otherClass表示传入的参数
    {
    #if __OBJC2__
        if (slowpath(!obj)) return NO;
        Class cls = obj->getIsa();//获取isa,根据传入的obj获取他的类或者元类
        if (fastpath(!cls->hasCustomCore())) {
            for (Class tcls = cls; tcls; tcls = tcls->superclass) {
                if (tcls == otherClass) return YES;
            }
            return NO;
        }
    #endif
        return ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass);
    }
    
    • 有点特殊的是re1,[NSObject class]的元类为根元类,根元类的superClass指向NSObject类对象所以re1的结果为yes。

    class方法

    • class有对象方法和实例方法,对应的实现如下
    + (Class)class { //对象方法返回自身
        return self;
    }
    - (Class)class {//实例方法返回isa,也就是类对象
        return object_getClass(self);
    }
    Class object_getClass(id obj)  //也可以通过这个方法获取元类
    {
        if (obj) return obj->getIsa();
        else return Nil;
    }
    
    • 通过源码调试发现外部调用class方法的时候也不是走的上述方法而是进入了objc_opt_class
    // Calls [obj class]
    Class
    objc_opt_class(id obj)
    {
    #if __OBJC2__
        if (slowpath(!obj)) return nil;
        Class cls = obj->getIsa();
        if (fastpath(!cls->hasCustomCore())) {
            return cls->isMetaClass() ? obj : cls;
        }
    #endif
        return ((Class(*)(id, SEL))objc_msgSend)(obj, @selector(class));
    }
    
    • 通过llvm代码可以看到编译器对一些方法进行了处理包括
    原方法 llvm处理后执行的方法
    allocWithZone objc_allocWithZone
    alloc objc_alloc
    new objc_opt_new
    self objc_opt_self
    class objc_opt_class
    isKindOfClass objc_opt_isKindOfClass
    respondsToSelector objc_opt_respondsToSelector
    ... ...

    相关文章

      网友评论

          本文标题:oc常用方法底层实现分析

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