美文网首页
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