美文网首页iOS 开发技巧大全
深入剖析OC Runtime(三) Message Forwa

深入剖析OC Runtime(三) Message Forwa

作者: ShawnDu | 来源:发表于2017-07-25 21:33 被阅读25次

深入剖析OC Runtime(三) Message Forward Demo
原文地址

objc_msgSend

objc_msgSend的格式如下:

void objc_msgSend(id self, SEL cmd, parameter...)

OC中所有的调用方法,属性赋值,都会转化为上面的C函数发送消息。找不到方法时,会走消息转发机制。

消息转发

先上图, 消息转发全流程

消息转发分为两大阶段。

  • 第一阶段先问接收者,所属的类,看能否动态添加方法,以处理这个未知的selector,这叫动态方法解析。
  • 第二阶段涉及完整的消息转发机制。
    如果运行期系统已经把第一阶段执行完了,那接收者自己就无法再以动态新增方法的手段来响应包含该selector的消息了。此时运行期系统会请求接收者以其他手段来处理与消息相关的方法调用。这又分为两步:a.请接发者看看有没有其他对象能处理这条消息,若有,则runtime会把消息转给那个对象,转发过程结束。若没备用的接收者,会启动完整的消息转发机制,runtime会把与消息有关的全部细节都封装在NSInvocation对象中,再给接收者最后一次机会。

示例

由开发者来添加属性的定义,并声明为@dynamic,此类会自动处理属性值的存放。
header中:

#import <Foundation/Foundation.h>

@interface SSAutoDictionary : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) NSDate *date;
@property (nonatomic, strong) NSNumber *number;
@end

上面定义了几种数据类型。
在实现文件中:

#import "SSAutoDictionary.h"
#import <objc/runtime.h>

@interface SSAutoDictionary()
@property (nonatomic, strong) NSMutableDictionary *backStore;
@end

@implementation SSAutoDictionary

@dynamic name, date, number;

- (id)init {
    if (self = [super init]) {
        _backStore = [NSMutableDictionary new];
    }
    return self;
}

假如只这样写,从外部访问属性的set和get方法时,都会找不到方法,所以引入了resolveInstanceMethod:

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    NSString *selectorString = NSStringFromSelector(sel);
    if ([selectorString hasPrefix:@"set"]) {
        class_addMethod(self, sel, (IMP)autoDictionarySetter, "v@:@");
    } else {
        class_addMethod(self, sel, (IMP)autoDictionaryGetter, "@@:");
    }
    return YES;
}

用前缀断定是否为set,两种情况下,都向类中新增一个处理该selector的子方法,这两个方法以函数指针形式出现autoDictionarySetter和autoDictionaryGetter。Getter方法:

id autoDictionaryGetter(id self, SEL _cmd) {
    SSAutoDictionary *mSelf = (SSAutoDictionary *)self;
    NSString *key = NSStringFromSelector(_cmd);
    return [mSelf.backStore objectForKey:key];
}

setter方法:

void autoDictionarySetter(id self, SEL _cmd, id value) {
    SSAutoDictionary *mSelf = (SSAutoDictionary *)self;
    NSString *selectorString = NSStringFromSelector(_cmd);
    NSMutableString *key = [selectorString mutableCopy];
    [key deleteCharactersInRange:NSMakeRange(key.length - 1, 1)];
    [key deleteCharactersInRange:NSMakeRange(0, 3)];
    NSString *lowercaseFirstChar = [[key substringToIndex:1] lowercaseString];
    [key replaceCharactersInRange:NSMakeRange(0, 1) withString:lowercaseFirstChar];
    if (value) {
        [mSelf.backStore setObject:value forKey:key];
    } else {
        [mSelf.backStore removeObjectForKey:key];
    }
}

使用的时候:

    SSAutoDictionary *dict = [SSAutoDictionary new];
    dict.date = [NSDate new];
    NSLog(@"dict.date = %@", dict.date);

输出:

RuntimeDemo[61043:9339954] dict.date = 2017-07-25 13:19:22 +0000

源码地址

Demo:https://github.com/dulingkang/Runtime

原文地址

相关文章

  • 深入剖析OC Runtime(三) Message Forwa

    深入剖析OC Runtime(三) Message Forward Demo原文地址 objc_msgSend ...

  • iOS runtime

    runtime是OC底层的一套C语言的API(引入或者...

  • 深入剖析OC Runtime(一) - Class MetaCl

    概要 Runtime是OC里面最牛逼的特点之一,所以对它的原理要知道一些,才能更好的去理解运行代码背后的一些原理。...

  • 深入剖析OC Runtime(二)-self super

    先上题目 Child.h: Child.m: Father.h: Father.m: 在main.m里面实例化ch...

  • 消息转发机制原理?

    iOS runtime探究(二): 从runtime开始深入理解OC消息转发机制https://www.jians...

  • iOS高性能OC三:Runtime Message

    1.消息发送objc_msgSendOC中在运行期决定调用什么方法,方法的调用转换成C函数 这个函数的参数个数可变...

  • Runtime 的理解

    Runtime是深入学习OC的必经之路,所以花了一些时间研究了一下。 一、介绍RunTime(运行时): OC 语...

  • objc_msgSend流程

    引入头文件:#import Runtime 给OC提供的运行时,装在内存中的代码...

  • iOS runtime详解

    引导 runtime是运行时,对于从事iOS开发,想要深入学习OC的人,runtime是必须熟悉掌握的东西。 ru...

  • RunTime的讲解

    Runtime 是 iOS 编程中比较难的模块,想要深入学习 OC,那 Runtime 是你必须要熟练掌握的东西,...

网友评论

    本文标题:深入剖析OC Runtime(三) Message Forwa

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