Objective-C运行时的一些技巧

Apple的iOS8发布以后,大家都开始了适配的工作了。但是这个过程总会遇到一些拦路虎,例如推送的API改动。可是商业项目上嵌入了各种各样的第三方静态库,这些静态库质量参差不齐,其中一个静态库甚至在Xcode6上编译后出现问题。于是只能使用Xcode5来编译,但这样就有一个很纠结的问题就是,UIMutableUserNotificationAction等一些类在旧版的Xcode要么就是无法编译,要么只能用宏来跳过。

这时候,我还是想起了Objective-C的运行时方法,使用NSClassFromString(@"UIMutableUserNotificationAction")来获取到系统的类。光这样子还是有很多不足,因为这个类中有很多方法、属性。虽然保证了运行的正常,但是编写这些方法还是有各种不便。例如各种performSelector:、objc_msgSend、setValue: forKey:,实在写得很痛苦。我这里用了一个比较取巧的方法,新建一个伪造的类如“XXXMutableUserNotificationAction”,继承NSObject即可。然后将UIMutableUserNotificationAction所有的属性和方法的声明添加到XXXMutableUserNotificationAction的头文件。以后,使用UIMutableUserNotificationAction时,就如下方:

1 Class XXXMutableUserNotificationActionClass = NSClassFromString(@"UIMutableUserNotificationAction");
2 XXXUIMutableUserNotificationAction *action = [[XXXMutableUserNotificationActionClass alloc] init];

既可以使用Xcode的补全提示,又可以通过编译。(如果大家有更好的方法,欢迎探讨探讨)

Object-C运行时的方法固然强大,但是使用这些方法还是有一定的风险。例如静态分析对于一些运行时的问题是检查不出来的,这里我举一个内存泄漏的例子。我的项目中使用了一些运行时添加属性的方法,同时为一些View添加了block类型的属性。在使用的时候,不小心在block中直接使用了self,就会出现编译器无法检查的内存泄露。泄漏路径:VC->View->block->VC,形成了循环引用。这种泄漏相对隐蔽一些,但对于经常RAC的童鞋来说,可能已经练就到百毒不侵了(^_^)。因为@weakify和@strongify的频繁使用,我对这类型泄漏已经比较敏感。__weak typeof(self) weakSelf = self,算是一种虽然难看,但是行之有效的方法,如果有兴趣也可以参考RAC的解决方案,本质上也是一样的。
题外话,BlockKit包含了一个很好用的分类“NSObject+BKAssociatedObjects”,可以用更友好的方法实现运行时添加属性,顺带一提bk_weaklyAssociateValue的实现思路相当巧妙,值得借鉴。

最后一个技巧是关于RAC和系统API的一些关系,先来看看一下两段代码:

1 UIGestureRecognizer *dismissKeyboardGR = [[UIGestureRecognizer alloc] init];
2 [self.view addGestureRecognizer:dismissKeyboardGR];
3 [[[self rac_signalForSelector:@selector(gestureRecognizer:shouldReceiveTouch:)
4                  fromProtocol:@protocol(UIGestureRecognizerDelegate)]
5   takeUntil:dismissKeyboardGR.rac_willDeallocSignal]
6   subscribeNext:^(id x) {
7       [Utils hideKeyboardInAllView];
8   }];
9 dismissKeyboardGR.delegate = self;
1 UIGestureRecognizer *dismissKeyboardGR = [[UIGestureRecognizer alloc] init];
2 [self.view addGestureRecognizer:dismissKeyboardGR];
3 dismissKeyboardGR.delegate = self;
4 [[[self rac_signalForSelector:@selector(gestureRecognizer:shouldReceiveTouch:)
5                  fromProtocol:@protocol(UIGestureRecognizerDelegate)]
6   takeUntil:dismissKeyboardGR.rac_willDeallocSignal]
7   subscribeNext:^(id x) {
8       [Utils hideKeyboardInAllView];
9   }];

先来看看这两段代码的区别只在于delegate的设置先后不一样,但这就造成了后一段代码在iOS6上就无法触发RAC里方法,iOS7上正常。为什么呢?

这涉及到一个类似缓存的机制。平时,我们会习惯使用respondsToSelector:来检查一个对象或者类是否实现了对应的方法,但频繁调用respondsToSelector:会对性能有一定的影响。特别是UITableView的dataSource一些方法,调用频率很高的。因此,在设置delegate后,UIGestureRecognizer使用了respondsToSelector:检查了一次self是否gestureRecognizer:shouldReceiveTouch:的方法,然后把这个结果缓存起来。由于RAC也使用了类似Method Swizzling方法,因此在设置delegate以后再使用RAC的方法,UIGestureRecognizer也只读取了缓存,并不会再次检查,所以认为self并未实现gestureRecognizer:shouldReceiveTouch:的方法,于是不作调用。(具体缓存的实现方法,可以参照http://www.cnblogs.com/ipinka/p/3862786.html)

时间: 2024-08-11 01:18:24

Objective-C运行时的一些技巧的相关文章

gdb调试运行时的程序小技巧

使用gdb调试运行时的程序小技巧 标签: 未分类 gdb pstack | 发表时间:2012-10-15 04:32 | 作者:士豪 分享到: 出处:http://rdc.taobao.com/blog/cs 原创文章,欢迎转载.转载请注明:转载自淘宝核心系统团队博客,谢谢! 原文链接地址: 使用gdb调试运行时的程序小技巧 下面介绍我调试时经常遇到的三种问题,如果大家也有类似的问题交流一下解决方法: 情景1:在不中止程序服务的情况下,怎么调试正在运行时的程序 情景2:需要同时看几个变量的值或

iOS彩票项目--第七天,初次读取json数据、KVC转模型技巧、运行时字典转模型以及初步对显示网页的操作并且跟踪标签

一.初次读取json数据 二.KVC转模型技巧,这里的技巧主要解决的是字典中的key 与 模型中有的属性对应不起来的时候 的解决办法 <方法1> <方法2>运行时字典转模型,运行时自己一直很晕.不过还是整理下来,方便以后用. 这里直接创建了一个分类. 头文件代码 1 // 2 // NSObject+Model.h 3 // Chaos_G 4 // 5 6 #import <Foundation/Foundation.h> 7 8 @interface NSObjec

[精通Objective-C]进阶技巧:使用运行时系统API

[精通Objective-C]进阶技巧:使用运行时系统API 参考书籍:<精通Objective-C>[美] Keith Lee 什么是运行时系统? 目录 精通Objective-C进阶技巧使用运行时系统API 目录 动态加载可选包 创建命令行程序 创建可选包 传入包路径 使用可选包 运行时系统API 动态代理 创建实现横切功能的协议和类 编写代理类 添加代理的目标类 测试动态代理程序 动态加载可选包 下面是使用NSbundle API动态加载自己编写的框架包的示例,共需要创建两个工程,一个命

[转]使用gdb调试运行时的程序小技巧

原创文章,欢迎转载.转载请注明:转载自淘宝核心系统团队博客,谢谢!原文链接地址:使用gdb调试运行时的程序小技巧 下面介绍我调试时经常遇到的三种问题,如果大家也有类似的问题交流一下解决方法:情景1:在不中止程序服务的情况下,怎么调试正在运行时的程序情景2:需要同时看几个变量的值或者批量查看多个core文件的堆栈信息怎么办情景3:遇到需要查看.队列.链表.树.堆等数据结构里的变量怎么办1. 情景1:在不中止程序服务的情况下,怎么调试正在运行时的程序我们在生产环境或者测试环境,会遇到一些异常,我们需

Xcode小技巧:使用代码块+查看某行代码作者+运行时显示控件边框

1.如果使用 git 来开发,可以快速定位你现在看不懂的代码是哪个2货写的,然后即使把锅甩到他身上(ps:如果是自己写的,你就默不作声,别让别人知道这个技巧哈),其实就是 show blame for line. 2.有句话说的好,聪明的程序员懂得"偷懒"来提升开发效率.我们在日常开发中,有一些代码片段会经常利用到,大家可能会觉得定义一些宏可以解决问题,但是遇到比如,UITableView的协议方法,或者写Demo时候想要快速的定义一个UIButton(当然,你用storyboard除

iOS Objective -C Runtime 运行时之一: 类与对象

// --------------------------------------------------- 参考:南峰子的技术博客 http://southpeak.github.io //---------------------------------------------------- OC语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理.这种动态语言的优势在于:我们编写代码时更具灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一个方法的实现等.

Objective-O Runtime 运行时初体验

Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理.这种动态语言的优势在于:我们写代码时更具灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一个方法的实现等. 这种特性意味着Objective-C不仅需要一个编译器,还需要一个运行时系统来执行编译的代码.对于Objective-C来说,这个运行时系统就像一个操作系统一样:它让所有的工作可以正常的运行.这个运行时系统即Objc Runtime.Objc Runtime其实是一个Runtime

iOS开发——高级特性&amp;Runtime运行时特性详解

Runtime运行时特性详解 本文详细整理了 Cocoa 的 Runtime 系统的知识,它使得 Objective-C 如虎添翼,具备了灵活的动态特性,使这门古老的语言焕发生机.主要内容如下: 引言 简介 与Runtime交互 Runtime术语 消息 动态方法解析 消息转发 健壮的实例变量(Non Fragile ivars) Objective-C Associated Objects Method Swizzling 总结 引言 曾经觉得Objc特别方便上手,面对着 Cocoa 中大量

iOS开发之runtime运行时机制

最近参加三次面试都有被问到runtime,也不知道面试官们自己懂不懂,反正就喜欢问,似乎就想把我唬住,来显示自己的对OC底层知识的理解很牛逼似的.(我现在开始看面试题,发现他们都喜欢问面试题的问题,我算明白了,都是应试教育惹的祸,大概他们以前没什么实际的app经验,所以准备了很多面试题,而我真的是能写app,先干活再找方法的人,面试不多,没什么面试经验,看来要开始碰壁多次才能掌握中国式面试).因为不太懂runtime我就只能支支吾吾的说点零碎.我真的好几次努力想看一看runtime的知识,因为知