转载

runtime从入门到放弃

本篇不适应 runtime 学习,也不涉及 runtime 长篇大论的理论知识。本篇只是想让你适当的学会放手。而所谓的入门到放弃中的 入门 则是一些 runtime 常用 apis 的认识和使用场景(笔者工作总结)。而所谓的放弃就是不要太过于执着 runtime ,其实它并没有你想象中的那么好。

来嗨起来

现在就让我们开始来旅游 runtime 的世界吧~!

关联

objc_setAssociatedObject 关联,懂点 runtime 或者不懂 runtime 的应该都知道这个家伙吧。再或者在分类里也应该见过不少了吧。不讲它用法,只分享笔者经历。

关联的用处一般是用来在分类里定义属性,分别在属性的 setget 方法里存放或者获取属性的值。当然还有一个用处也比较实用,则是强引用自己,并且不要释放。

强引用自己?嗯哼?怎么有一点晕晕的。好吧,举个列子。

需求(可忽略):

比如你有一个 ZXPAAAclass ,然后 ZXPAAA 里有 showdismiss 方法,并且还有一个 delegate 回调。然后你还有一个 ZXPBBBclass 并且有一个函数叫 test 。现在 test 函数里有一个局部自动变量 ZXPAAA 的实例,并且调用 ZXPAAA的show 方法来弹出一个视图。

那么问题来了,这时候你在 ZXPBBB的test方法 里设置 ZXPAAA 的delegate为 self (self=ZXPBBB)的时候,因为 ZXPAAA 是局部自动变量,所以在 test 函数执行完之前,函数内部的 ZXPAAA 实例变量的引用计数会减一,由于你只是实例化了一下,引用计数为一,然后在减一,故此,此变量会释放,然后在这时候你遵守的 ZXPAAA 的delegate方法永远不会回调。

解决:那么这时候你就可以在 ZXPAAA 里的 show 方法用objc_setAssociatedObject来关联自己并设置 retain 引用+1。让self不会释放,代码如下:

//ZXPAAA的show 方法里,关联自己,会引用计数+1
objc_setAssociatedObject(self, key, self, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

目前为止确实是解决了对象自动释放的问题,可问题是对象一直存在呀。内存泄露了尼。不用怕,我们在ZXPAAA的dismiss 方法里释放关联就行了。代码如下:

//ZXPAAA的dismiss 方法里,从关联里移除,设置为nil,会引用计数-1
objc_setAssociatedObject(self, key, nil, OBJC_ASSOCIATION_ASSIGN);

之前简单封装了一个pickerView工具类里面有用到类似场景,点此进行传输进行查看。

获取class的所有方法(包含私有)

核心方法是 class_copyMethodList ,直接贴代码:

uint count;
//返回值是一个Method指针
Method *methodList = class_copyMethodList([NSObject class], &count);

for ( int i = 0 ; i < count; i++) {
NSLog(@"%@",NSStringFromSelector(method_getName(methodList[i])));
}

//释放
free(methodList);

以上这串代码,看似很牛逼。。其实用一句话来形容就是 just so so 而已。其实最主要的是并没有任何一点实际用处。就算知道了很多私有方法,你想去完美的运用它也需要很多时间成本,而且 app store 还不会给你上线(企业发布除外)。

PS:更多用法直接去查看.h文件即可。

获取class的所有变量(包含私有)

核心方法是 class_copyIvarList ,直接贴代码:

uint count;

//返回值是一个Ivar指针
Ivar *ivarList = class_copyIvarList([UIViewController class], &count);

for ( int i = 0 ; i < count; i++) {
NSLog(@"%s",ivar_getName(ivarList[i]));
}

//释放
free(ivarList);

获取变量和获取方法同理,然并卵,但作为兴趣研究研究的话,还是可以玩玩的。在工程里的实际用处也并不大。

PS:更多用法直接去查看.h文件即可。

方法替换

API为 method_exchangeImplementations ,交换两个方法的实现,一般用来进行黑魔法调试。虽然也可以用来实现AOP切面编程,but…工程里千万慎用,千万慎用,千万慎用。重要的事情说三遍,至于为什么,原因很简单,不好维护,出了错都不知道飞哪儿去了。而要实现方法切面可使用开源的 Aspects

PS: 所谓的黑魔法调试,比如替换init方法,并打印一句话,方便我们知道哪些class被初始化,而AOP切面编程的概念网上也有很多,随意百度一下即可。

其他

其他还有很多,比如 objc_copyClassList 获取所有class, method_setImplementation 给方法重置一个IMP等等。关于runtime的API有点太多了,就不一一列举了。当然关于runtime知识点远不止这些api这么简单,比如消息转发,重定向等等。

写在最后

but…. runtime有这么多的api,到底有什么用?答案是并没什么卵用,对,虽然没卵用,但还是很重要,不要问我为什么,就因为它是OC底层,核心。作为一位iOSer,了解这些基础是必须的,起码装逼也有了资本。再退一万步来讲,对于面试,这些也会派上用场。不过对于工作中,确实没啥太大的用处,但是如果写框架的话,用处还是特别大,而且作为程序员也不能一直停留在应用层层面。

当然,在工作中用的并不怎么多,但是,还是必须要学的。而标题所谓的放弃的寓意是,让你不要太过于纠结runtime到底有什么用。因为也有很多新人问过笔者runtime到底能做什么….况且现在关于这方面的资料也不多。资料查来查去无非就是消息转发,重定向还有那几个获取变量、方法等几个常用的API而已。当然,对于runtime笔者也连门都没有入。。在此笔者建议新人们一直捉摸不透runtime到底能做什么,倒不如花花时间去研究一下GCD,core foundation等。

以上纯属笔者个人给新人的一些建议以及一些runtime肤浅的用法。欢迎吐槽,请勿喷贴。。。

转载请注明原文出处

runtime从入门到放弃

原文  http://xiaopingblog.cn/2016/05/06/runtime从入门到放弃/
正文到此结束
Loading...