iOS--RunTime原理

iOS runtime原理class isa

2020-02-19  本文已影响0人  我嘞giaogiao

runtime class isa

所有继承自 NSObject 的类实例化后的对象都会包含一个类型为 isa_t 的结构体。不只是实例会包含一个 isa 结构体,所有的类也有这么一个 isa

struct objc_object {
private:
isa_t isa;
...
}

最关键的就是isa_t这个类型和一系列的构造函数,点击查看isa_t发现这是一个联合体:


union isa_t 
{
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }
    Class cls;
}

可以看到这个联合体里面有个Class类型的属性cls,看起来里面应该是关于这个对象的类的相关信息,那我们再看看Class包含了哪些内容。

struct objc_class : objc_object {
    // Class ISA;
    Class superclass;
    cache_t cache;             // 方法缓存
    class_data_bits_t bits;    //bits 里面存放这当前类属性,方法、协议等信息
    ...
}

由此可见Class是一个objc_class类型的结构体,而objc_class继承自objc_object,说明类也是一个对象,只是比普通的对象多了一些属性,比如superclass等。

实验:

TestObject *testObj = [TestObject new];
NSLog(@"%d", [testObj class] == [TestObject class]);

这个log会输出1(为true)

不好理解,看下具体源码,如下

+ (Class)class {
    return self;
}
- (Class)class {
    return object_getClass(self);
}

object_getClass方法最终返回的是isa。所以TestObject调用class方法,返回的是自身;testObj调用class方法,返回的是isa指向的类,也是TestObject。

举一反三:

[self class] 与 [super class]

@implementation Son : Father
   - (id)init
   {
       self = [super init];
       if (self) {
           NSLog(@"%@", NSStringFromClass([self class]));
           NSLog(@"%@", NSStringFromClass([super class]));
       }
       return self;
   }
   @end

眼熟,在哪里见过你,是的,很多有笔试经历小伙伴会碰到这题,看似很简单,但是被问为什么的时候?这么简单,居然问为什么,当时还是太嫩了,还是太年轻了。

详解:

NSStringFromClass([self class]) = Son
NSStringFromClass([super class]) = Son

self 是类的隐藏参数,指向当前调用方法的这个类的实例;
super 本质是一个编译器标示符,和 self 是指向的同一个消息接受者。不同点在于:super 会告诉编译器,当调用方法时,去调用父类的方法,而不是本类中的方法。

当使用 self 调用方法时,会从当前类的方法列表中开始找,如果没有,就从父类中再找;而当使用 super 时,则从父类的方法列表中开始找。然后调用父类的这个方法。

在调用[super class]的时候,runtime会去调用objc_msgSendSuper方法,而不是objc_msgSend;

OBJC_EXPORT void objc_msgSendSuper(void /* struct objc_super *super, SEL op, ... */ )

/// Specifies the superclass of an instance. 
struct objc_super {
    /// Specifies an instance of a class.
    __unsafe_unretained id receiver;

    /// Specifies the particular superclass of the instance to message. 
#if !defined(__cplusplus)  &&  !__OBJC2__
    /* For compatibility with old objc-runtime.h header */
    __unsafe_unretained Class class;
#else
    __unsafe_unretained Class super_class;
#endif
    /* super_class is the first class to search */
};

在objc_msgSendSuper方法中,第一个参数是一个objc_super的结构体,这个结构体里面有两个变量,一个是接收消息的receiver,一个是当前类的父类super_class。

objc_msgSendSuper的工作原理应该是这样的:
从objc_super结构体指向的superClass父类的方法列表开始查找selector,找到后以objc->receiver去调用父类的这个selector。注意,最后的调用者是objc->receiver,而不是super_class!

那么objc_msgSendSuper最后就转变成:

// 注意这里是从父类开始msgSend,而不是从本类开始
objc_msgSend(objc_super->receiver, @selector(class))

/// Specifies an instance of a class.  这是类的一个实例
    __unsafe_unretained id receiver;   


// 由于是实例调用,所以是减号方法
- (Class)class {
    return object_getClass(self);
}
这里 其实就是 [self class] == [Son class] ,又回到之前讲过的isa知识了

由于找到了父类NSObject里面的class方法的IMP(一个函数指针,保存了方法的地址),又因为传入的入参objc_super->receiver = self。self就是son,调用class,所以父类的方法class执行IMP之后,输出还是son,最后输出两个都一样,都是输出son。

上一篇 下一篇

猜你喜欢

热点阅读