Apple的iOS8发布之后,你们都开始了适配的工做了。可是这个过程总会遇到一些拦路虎,例如推送的API改动。但是商业项目上嵌入了各类各样的第三方静态库,这些静态库质量良莠不齐,其中一个静态库甚至在Xcode6上编译后出现问题。因而只能使用Xcode5来编译,但这样就有一个很纠结的问题就是,UIMutableUserNotificationAction等一些类在旧版的Xcode要么就是没法编译,要么只能用宏来跳过。html
这时候,我仍是想起了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的补全提示,又能够经过编译。(若是你们有更好的方法,欢迎探讨探讨)ide
Object-C运行时的方法当然强大,可是使用这些方法仍是有必定的风险。例如静态分析对于一些运行时的问题是检查不出来的,这里我举一个内存泄漏的例子。性能
ui
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上正常。为何呢?spa
这涉及到一个相似缓存的机制。平时,咱们会习惯使用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)code