Runtime底层学习

2018-11-16  本文已影响0人  朝夕向背

Objective-C作为一门高级编程语言,想要成为可执行文件需要先编译成汇编语言,在汇编成机器语言,机器语言也是计算机能识别的唯一语言。但是Objective-C并不能直接编译成汇编语言,需要先转写为C语言在进行编译和汇编的操作。从Objective-C到C语言的过渡就是由Runtime来实现的。
Objective-C的语言特性是动态性比较强,这种动态性就是由Runtime API来支撑的。想要了解Runtime的原理,首先需要知道OC语言的isaCache缓存class_rw_t

isa详解

要想学习Runtime,首先要了解它底层的一些常用的数据结构,比如isa指针。
在arm64架构之前,isa就是一个普通的指针,存储着Class、Meta-Class对象的内存地址。
从arm64架构开始,对isa进行了优化,变成了一个共用体(union)结构,还使用位域来存储更多的信息。共用体如下

union isa_t 
{
    Class cls;
    uintptr_t bits;
    struct {
        uintptr_t nonpointer        : 1;
        uintptr_t has_assoc         : 1;
        uintptr_t has_cxx_dtor      : 1;
        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;
        uintptr_t extra_rc          : 19;
    };

我们来看一段代码

#import <Foundation/Foundation.h>

@interface Person : NSObject
@property (nonatomic,  assign, getter=isTall) BOOL tall;
@property (nonatomic,  assign, getter=isRich) BOOL rich;
@property (nonatomic,  assign, getter=isHandsome) BOOL handsome;
@end

#import "Person.h"

@implementation Person

@end

#import <Foundation/Foundation.h>
#import "Person.h"
#import <objc/runtime.h>
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *person = [[Person alloc] init];
        person.rich = NO;
        person.tall = YES;
        person.handsome = NO;
        NSLog(@"%zd",class_getInstanceSize([Person class]));
    }
    return 0;
}

在main.m函数中,系统给Person对象分配了16个字节的内存,其中Person的isa指针占用8个字节,三个属性占用3个字节。
既然Person的属性是BOOL类型,可以考虑使用共用体。

共用体:共用体内的成员变量共用一块内存。

Person类的.m文件内,可以修改成如下:

#import "Person.h"

@interface Person()
{
    union{
        char bits;
        struct{
            char tall : 1;
            char rich : 1;
            char handsome  : 1;
        };
    }_tallRichHandsome;
}
@end

@implementation Person

- (void)setTall:(BOOL)tall{
    _tallRichHandsome.bits = tall;
}
- (BOOL)isTall{
    return !!(_tallRichHandsome.bits );
}

- (void)setRich:(BOOL)rich{
    _tallRichHandsome.bits = rich;
}
- (BOOL)isRich{
    return !!(_tallRichHandsome.bits);
}

- (void)setHandsome:(BOOL)handsome{
    _tallRichHandsome.bits = handsome;
}
- (BOOL)isHandsome{
    return !!( _tallRichHandsome.bits);
}
@end

在结构体union中

       struct{
            char tall : 1;
            char rich : 1;
            char handsome  : 1;
        };

只是为了方便阅读代码,struct内的成员变量,都存储在unionchar中。所以回到开头的union isa_t中,struct是为了阅读方便,共用体union中的信息都存储在uintptr_t bits;中。

Class的结构

objc_class的结构

方法缓存

Class内部结构中有个方法缓存(cache_t),用散列表来缓存曾经调用的方法,可以提高方法的查找速度。

cache_t
buckets是散列表,是数组。
bucket_t

objc_msgSend

先来看段代码

#import <Foundation/Foundation.h>

@interface Person : NSObject
- (void)personTest;
@end

#import "Person.h"

@implementation Person
- (void)personTest{

}
@end

#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *person = [[Person alloc] init];
       [person personTest];
    }
    return 0;
}

当调用- (void)personTest;方法时,是在底层转化为C语言调用

int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
        Person *person = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc")), sel_registerName("init"));
        ((void (*)(id, SEL))(void *)objc_msgSend)((id)person, sel_registerName("personTest"));
    }
    return 0;
}

✔️ 消息发送

✔️动态方法解析

✔️消息转发

注意:
1、如果调用的是类方法,上述流程中,方法换成类方法(+开头)。
2、dynamic告诉编译器不要自动生成setter方法和getter方法的实现,等到运行时在添加方法的实现。
3、@synthesize age = _age;是为age属性生成_age,并且自动生成setter方法和getter方法,并赋值。

有关super

[super message]的底层实现

objc_msgSendSuper(self,[Person class],@selector(message));

[super class]返回的是当前类

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

[super superClass]返回的是父类

- (Class)superclass{
     return class_getSuperclass(object_getClass(self));
}

Runtime的应用API

类相关
成员变量相关
属性相关
方法相关
上一篇下一篇

猜你喜欢

热点阅读