iOS OC的Runtime详解

方法的实质

在OC中,方法的实质其实是两部分组成:

1.方法的代号(SEL),

2.方法的实现(IMP),

对象调用方法,实际上就是一个发送消息的过程.

比如[person eat];其实等价于:

objc_msgSend(person, @selector(eat));

objc_msgSend(person, NSSelectorFromString(@"eat"));

objc_msgSend(person, sel_registerName("eat"));

再比如我们最熟悉的初始化方法

Person *person = [[Person alloc]init];

在底层其实是这样实现的:

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"));

ps:为能编译过需要把 Buid Setting  msg 设置为NO并且导入<objc/runtime.h>

Runtime的作用

上面其实就是调用了苹果提供的RuntimeAPI,即程序运行时.对于我们开发者来讲,其实主要有3个用处:

1.在程序运行的过程中,动态的创建一个类

2.在程序运行的过程中,动态的为某个类添加/修改方法/属性

3.在程序运行的过程中,动态的遍历类的所有方法和成员变量

下面其实都是runtime这些用法的实现.

方法的"懒加载"

首先我们知道,NSObject有如下两个方法:

+ (BOOL)resolveClassMethod:(SEL)sel;
+ (BOOL)resolveInstanceMethod:(SEL)sel;

前者是当类调用了没有实现的(就是缺少sel/imp)类方法时调用,后者则是调用了未实现的实例方法时调用.

例如:上面的Person * p = [[Person alloc]init];

我并没有实现run:方法,但是当我

   [p performSelector:@selector(run:) withObject:@"100"];

程序当然毫无悬念的崩溃了🤣.

然而现在操蛋的需求是,让person表面上在跑,实际上在飞,程序还不能崩...这怎么可能!!!!!!?

但是,为了实现需求,我突然想到之前提到的方法:

#import "Person.h"

@implementation Person

//当类调用了没有实现的实例方法,会到这来

+ (BOOL)resolveInstanceMethod:(SEL)sel{

//这是添加方法实现,类似懒加载

//prama:1.类,2.方法编号SEL,3.方法实现IMP(函数指针),4.返回值类型(可以为"")

class_addMethod(self,  sel, (IMP)fly, "v@:@");

return [super resolveInstanceMethod:sel];

}

void fly(id self,SEL _cmd,NSString* distance){

NSLog(@"我就想飞!飞了%@米",distance);

};

以上代码的原理是:

我们调用run:方法其实是发消息:

objc_msgSend(p, @selector(run:), @"100");

所以实现fly函数时,要接收(p, @selector(run:), @"100")这3个参数

这时就实现了"我就想飞!飞了100米",因为fly是当我们调用时才去加载的,类似于属性的懒加载,故而我们可以说是方法的"懒加载"

ps:我们可以发现OC方法调用时会默认传递两个参数,id self 和 方法代号 sel.

Hook(钩子)

runtime最常见的用法,实现方法的欺骗,直接上代码:

//在load里下钩子(load = 编译前加载)

+ (void)load{

//方法欺骗(替换)

//本来的方法

Method sysMethod = class_getClassMethod([NSURL class], @selector(URLWithString:));

//自定义的方法

Method bbMethod = class_getClassMethod([NSURL class], @selector(BBURLWithString:));

//交换

method_exchangeImplementations(sysMethod, bbMethod);

}

//改URLWithString:方法,能判断空的URL,如果为空返回百度 (交换后如果再掉系统方法会递归奔溃 所以需要写注释)

+ (instancetype)BBURLWithString:(NSString *)URLString{

NSURL *url = [NSURL BBURLWithString:URLString];

if (url == nil || [URLString isEqualToString:@""]) NSLog(@"url 为 空");

return [NSURL URLWithString:@"http://www.baidu.com"];

}

return url;

}

KVO

我们都知道,一个KVO的实现,实际上就是观察属性的setter方法,因此我们实现一个KVO需要几个步骤:

1.动态派生 类的子类(NSKVONotyfing_person)

2.重写setter方法

3.方法中

[self willChangeValueForKey:@"name"]

[super setName:name];

[self didChangeValueForKey:@"name"];

未完待续................................

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

推荐阅读更多精彩内容