03进阶之路-Runtime

1. 类Runtime数据结构

学习链接

  • objc_class (类对象)
struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class _Nullable super_class                              OBJC2_UNAVAILABLE;
    const char * _Nonnull name                               OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;
这是已经失效的类对象的结构,但是也反映了类对象基本数据结构
真实的类对象的结构是
objc_class
isa_t isa
Class superClass
cache_t cache
class_data_bits_t bits
  • class_data_bits_t 结构
其中只含有一个 64 位的 bits 用于存储与类有关的信息:
64位数据包含了 四个信息
第 [3, 47] 位 :class_rw_t * 指针只存于第 [3, 47] 位
第0位: isSwift():FAST_IS_SWIFT 用于判断 Swift 类
第1位:hasDefaultRR():FAST_HAS_DEFAULT_RR 当前类或者父类含有默认的retain/release/autorelease/retainCount/_tryRetain/_isDeallocating/retainWeakReference/allowsWeakReference 方法
第2位:requiresRawIsa():FAST_REQUIRES_RAW_ISA 当前类的实例需要 raw isa
  • class_rw_t 和 class_ro_t 结构


    03进阶之路-Runtime_第1张图片
    image
  • method_t

struct method_t {
    SEL name;
    const char *types;
    IMP imp;
};
  • Type Encodings 类型编码

2. 类对象和元类对象和消息传递

  • 类对象

    继承自objc_class
    存储实例方法,变量,属性列表,协议列表
    
  • 元类对象

    根元类继承根类对象
    存储对象方法
    看懂下图就明白了
    
03进阶之路-Runtime_第2张图片
image
  • 消息传递

    实例类调用实例方法通过isa指针找到他的类对象,在类对象的缓存列表里面查找,没有找到在自己的实例方法列表里面查找,没有在沿着父类的指针查找下去,根类对象都没有,进入消息转发流程

    调用类方法:类对象通过isa指针找到元类对象,在元类对象的缓存列表里面查找,没有找到通过父类指针继续查找,根元类没有,就到根类对象的实例方法查找(注意根元类的superclass是根类对象),有就调用,没有进行消息转发

3. 方法缓存查找

计算机局部性原理的应用
hashMap实现,以方法名为key,在里面查找

4. 消息转发

学习链接
如果一个方法没有实现,消息传递机制结束之后就会进入消息转发流程,给我们三次拯救的机会

首先调用 +(BOOL)resolveInstanceMethod:(SEL)sel或者+ (BOOL)resolveClassMethod:(SEL)sel
给我们一次动态实现的机会,如果返回yes 会重新走一遍消息传递的流程

第二次调用-(id)forwardingTargetForSelector:(SEL)aSelector 
给我们一次转发给其他对象,如果返回一个非nil.消息将会转发给该对象

第三次调用- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector方法来获取这个选择子的方法签名.然后在- (void)forwardInvocation:(NSInvocation *)anInvocation处理
03进阶之路-Runtime_第3张图片
image

5. 黑魔法Method-Swizzling

就是imp指针混写技术.可以改变系统方法.hook系统方法,注意在load方法里面替换.

6. 动态添加方法

oid speak(id self, SEL _cmd){
    NSLog(@"Now I can speak.");
}
+ (BOOL)resolveInstanceMethod:(SEL)sel {
    
    NSLog(@"resolveInstanceMethod:  %@", NSStringFromSelector(sel));
    if (sel == @selector(speak)) {
        class_addMethod([self class], sel, (IMP)speak, "V@:");
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}

7. 动态方法解析

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    NSLog(@"forwardInvocation: %@", NSStringFromSelector([anInvocation selector]));
    if ([anInvocation selector] == @selector(code)) {
        Monkey *monkey = [[Monkey alloc] init];
        [anInvocation invokeWithTarget:monkey];
    }   
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    NSLog(@"method signature for selector: %@", NSStringFromSelector(aSelector));
    if (aSelector == @selector(code)) {
        return [NSMethodSignature signatureWithObjCTypes:"V@:@"];
    }
    return [super methodSignatureForSelector:aSelector];
}

你可能感兴趣的:(03进阶之路-Runtime)