本篇不适应 runtime
学习,也不涉及 runtime
长篇大论的理论知识。本篇只是想让你适当的学会放手。而所谓的入门到放弃中的 入门
则是一些 runtime
常用 apis
的认识和使用场景(笔者工作总结)。而所谓的放弃就是不要太过于执着 runtime
,其实它并没有你想象中的那么好。
现在就让我们开始来旅游 runtime
的世界吧~!
objc_setAssociatedObject
关联,懂点 runtime
或者不懂 runtime
的应该都知道这个家伙吧。再或者在分类里也应该见过不少了吧。不讲它用法,只分享笔者经历。
关联的用处一般是用来在分类里定义属性,分别在属性的 set
和 get
方法里存放或者获取属性的值。当然还有一个用处也比较实用,则是强引用自己,并且不要释放。
强引用自己?嗯哼?怎么有一点晕晕的。好吧,举个列子。
需求(可忽略):
比如你有一个 ZXPAAA
的 class
,然后 ZXPAAA
里有 show
和 dismiss
方法,并且还有一个 delegate
回调。然后你还有一个 ZXPBBB
的 class
并且有一个函数叫 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_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_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肤浅的用法。欢迎吐槽,请勿喷贴。。。
转载请注明原文出处