runtime从入门到放弃

本篇福利,用美女来抛砖引玉。
来点福利

GG 背景

本篇不适应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不会释放,代码如下:

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

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

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

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

乐一乐

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

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

1
2
3
4
5
6
7
8
9
10
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,直接贴代码:

1
2
3
4
5
6
7
8
9
10
11
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肤浅的用法。
欢迎吐槽,请勿喷贴。。。

转载请注明原文出处

最近很流行的

文章目录
  1. 1. GG 背景
  2. 2. 来嗨起来
    1. 2.1. 关联
    2. 2.2. 获取class的所有方法(包含私有)
    3. 2.3. 获取class的所有变量(包含私有)
    4. 2.4. 方法替换
    5. 2.5. 其他
  3. 3. 写在最后