runtime

什么是runtime?

1> runtime是一套底层的C语言API(包含很多强大实用的C语言数据类型、C语言函数)
2> 实际上,平时我们编写的OC代码,底层都是基于runtime实现的

  • 也就是说,平时我们编写的OC代码,最终都是转成了底层的runtime代码(C语言代码)

runtime有啥用?

1> 能动态产生一个类、一个成员变量、一个方法
2> 能动态修改一个类、一个成员变量、一个方法
3> 能动态删除一个类、一个成员变量、一个方法

常见的函数、头文件

成员变量、类、方法
#import <objc/runtime.h>

获得某个类内部的所有成员变量
Ivar * class_copyIvarList

获得某个类内部的所有方法
Method * class_copyMethodList

获得某个实例方法(对象方法,减号-开头)
Method class_getInstanceMethod

获得某个类方法(加号+开头)
Method class_getClassMethod

交换2个方法的具体实现
method_exchangeImplementations

消息机制
#import <objc/message.h> objc_msgSend(....)

  • @param receiver 消息接收者
  • @param selector 消息对应的方法名字
  • @param arg1.arg2...消息中的任意数目的参数
    objc_msgSend(receiver, selector, arg1, arg2, ...)

获取某个类的所有成员变量(延伸作用是归档、解档)

- (void)testRuntimeIvar
{
    // Ivar : 成员变量
    unsigned int count = 0;
    // 获得所有的成员变量
    //指针可以理解成为数组(根据1、2、3进行取值)
    Ivar *ivars = class_copyIvarList([HMPerson class], &count);
    for (int i = 0; i<count; i++) {
        // 取得i位置的成员变量
        Ivar ivar = ivars[i];
        const char *name = ivar_getName(ivar);
        const char *type = ivar_getTypeEncoding(ivar);
        NSLog(@"%d %s %s", i, name, type);
    }
    
    //    HMPerson *p = [[HMPerson alloc] init];
    //    objc_msgSend(p, @selector(setAge:), 20);
    
    //    NSLog(@"%d", p.age);
}

归档示例

- (void)encodeWithCoder:(NSCoder *)encoder
{
    unsigned int count = 0;
    Ivar *ivars = class_copyIvarList([HMPerson class], &count);
    for (int i = 0; i<count; i++) {
        // 取得i位置的成员变量
        Ivar ivar = ivars[i];
        const char *name = ivar_getName(ivar);
        NSString *key = [NSString stringWithUTF8String:name];
        [encoder encodeObject:[self valueForKeyPath:key] forKey:key];
    }
}

交换两个方法的实现

交换方法
OBJC_EXPORT void method_exchangeImplementations(Method m1, Method m2)

获得方法
Method class_getClassMethod(Class cls, SEL name)

例:

  • 分类加载进内存的时候会调用load方法,只会调用一次。当使用这个方法的时候,不需要声明也不需要写.h方法。因为所有.m方法都会加入内存中,调用到load中。

  • 实现了imageWithName:imageNamed:方法的交换,需要注意的问题是再重写imageWithName:时候不要在内部使用imageNamed:方法

#import <objc/runtime.h>

@implementation UIImage (Extension)
/**
 *  只要分类被装载到内存中,就会调用1次
 */
+ (void)load
{
    Method otherMehtod = class_getClassMethod(self, @selector(imageWithName:));
    Method originMehtod = class_getClassMethod(self, @selector(imageNamed:));
    // 交换2个方法的实现
    method_exchangeImplementations(otherMehtod, originMehtod);
}

+ (UIImage *)imageWithName:(NSString *)name
{
    BOOL iOS7 = [[UIDevice currentDevice].systemVersion floatValue] >= 7.0;
    UIImage *image = nil;
    if (iOS7) {
        NSString *newName = [name stringByAppendingString:@"_os7"];
        image = [UIImage imageWithName:newName];
    }
    
    if (image == nil) {
        image = [UIImage imageWithName:name];
    }
    return image;
}

获得方法地址

  • 编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。

避免动态绑定的唯一办法就是取得方法的地址,并且直接象函数调用一样调用它。当一个方法会被连续调 用很多次,而且您希望节省每次调用方法都要发送消息的开销时,使用方法地址来调用方法就显得很有效。

利用 Cocoa 运行时系统的提供的功能 methodForSelector: 实现某个方法


    
    void (*setter)(id, SEL, BOOL);
    
    setter = (void (*)(id, SEL, BOOL))[target methodForSelector:@selector(setFilled)];
    
    for (NSInteger i = 0; i < 100; i++) {
        setter(target,@selector(setFilled),YES);
    }

- (void)setFilled
{
    NSLog(@"123");
}

使用 methodForSelector:来避免动态绑定将减少大部分消息的开销,但是这只有在指定的消息被重 复发送很多次时才有意义,例如上面的 for 循环。
注意,methodForSelector:Cocoa运行时系统的提供的功能,而不是Objective-C语言本身的功 能。

消息机制

消息
消息

当对象收到消息时,消息函数首先根据该对象的isa指针找到该对象所对应的类的方法表,并从表中寻找 该消息对应的方法选标。如果找不到,objc_msgSend 将继续从父类中寻找,直到 NSObject 类。一 旦找到了方法选标, objc_msgSend 则以消息接收者对象为参数调用,调用该选标对应的方法实现。
这就是在运行时系统中选择方法实现的方式。在面向对象编程中,一般称作方法和消息动态绑定的过程。

为了加快消息的处理过程,运行时系统通常会将使用过的方法选标和方法实现的地址放入缓存中。每个类
都有一个独立的缓存,同时包括继承的方法和在该类中定义的方法。消息函数会首先检查消息接收者对象
对应的类的缓存(理论上,如果一个方法被使用过一次,那么它很可能被再次使用)。如果在缓存中已经
有了需要的方法选标,则消息仅仅比函数调用慢一点点。如果程序运行了足够长的时间,几乎每个消息都
能在缓存中找到方法实现。程序运行时,缓存也将随着新的消息的增加而增加。

消息转发

如果一个对象收到一条无法处理的消息,运行时系统会在抛出错误前,给该对象发送一条
forwardInvocation:消息,该消息的唯一参数是个 NSInvocation 类型的对象——该对象封装了 原始的消息和消息的参数。

防止crash


- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    
    //Person实现了`invocation selector`方法
    return [Person instanceMethodSignatureForSelector:aSelector];
    
    //传递参数到forwardInvocation: 的invocation的key,采用的是传递方式的办法
    //   return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
    
}


- (void)forwardInvocation:(NSInvocation *)invocation
{
    Person *person = [[Person alloc] init];
//
//    NSString *key = NSStringFromSelector([invocation selector]);
    
     NSString *sel = NSStringFromSelector([invocation selector]);
     NSLog(@"%@",sel);
    
    
    if ([person respondsToSelector:
         [invocation selector]])
        [invocation invokeWithTarget:person];
    
    else
        NSLog(@"nothing");
    //程序会crash
//    [super forwardInvocation:invocation]
}

参考资料:

链接: [http://pan.baidu.com/s/1i3JB56d][jekyll - DB] 密码: cmh6
[jekyll - DB]: http://pan.baidu.com/s/1i3JB56d

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,492评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,048评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,927评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,293评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,309评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,024评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,638评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,546评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,073评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,188评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,321评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,998评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,678评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,186评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,303评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,663评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,330评论 2 358

推荐阅读更多精彩内容