調(diào)用高版本API會有什么問題?
在iOS7上鲤嫡,調(diào)用iOS8新加入的方法會導(dǎo)致崩潰送挑。
- (BOOL) findString:(NSString *)s inString:(NSString *)destString {
NSString * lowDest = destString.lowercaseString;
return [lowDest containsString:s];
}
NSString
的containsString
方法是在iOS8才被加入的,只要在iOS7上調(diào)用了containsString
方法就會直接崩潰:
在iOS7上初始化iOS8才有的對象會返回nil暖眼。雖然不會崩潰惕耕,但是可能會導(dǎo)致預(yù)料外的行為。
LAContext* context = [[LAContext alloc] init];
self.touchIDEnabled =
[context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
error:&error];
LAContext
是一個iOS8才加入的對象诫肠。在iOS7上司澎,[[LAContext alloc] init]
會返回nil。
調(diào)用context
的canEvaluatePolicy:error:
方法栋豫,依然返回nil挤安。self.touchIDEnabled
就被設(shè)置成了NO。
按照代碼邏輯丧鸯,在iOS7上self.touchIDEnabled
恰好就應(yīng)該被設(shè)置為NO蛤铜,在這個例子中不會有更嚴(yán)重的問題發(fā)生,但如果這個變量是self.touchIDDisabled
丛肢,事情就不好說了围肥。
一定要用低版本系統(tǒng)不支持的API的時候該怎么辦?
iOS系統(tǒng)更新會帶來新的接口和特性,我們總是會遇到不得不用新版本API的情況蜂怎,所以代碼中必須兼容新舊兩種系統(tǒng):
- 通過判斷iOS系統(tǒng)版本來兼容
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
// Do something
}
- 在調(diào)用API前檢查
respondsToSelector
if ([cell respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)]) {
[cell setPreservesSuperviewLayoutMargins:NO];
}
- 在創(chuàng)建對象時判斷
[ClassName class]
是否為nil
- (BOOL)alertControllerAvailable {
return [UIAlertController class] != nil; // iOS 8 and later.
}
從代碼的可維護(hù)性來考慮穆刻,比較推薦后兩種方式近范。
檢查API可用性的工具
比較好的方案是用MJGAvailability.h在編譯期檢查巧鸭。
把MJGAvailability.h文件加入工程中,在預(yù)編譯頭文件最開頭加上下面的代碼即可:
#define __IPHONE_OS_VERSION_SOFT_MAX_REQUIRED __IPHONE_7_0
#import "MJGAvailability.h"
其中的__IPHONE_7_0
定義在Availability.h文件中荆陆,可以改成需要的任何系統(tǒng)版本篮愉。
配置完成后腐芍,調(diào)用不可用的API會出現(xiàn)如下形式的警告:
xxxxxxx.m:64:18: 'containsString:' is deprecated: TOO NEW!
如果配置后編譯沒有生效,把Build Settings里面的Enable Modules (C and Objective-C)
項改為NO試試试躏,具體原因我還不知道是為什么猪勇。
這個工具無法檢查出我們的代碼有沒有進(jìn)行過版本兼容處理,它會對所有有問題的代碼報錯颠蕴。所以我們要在處理過兼容性的地方泣刹,顯式的用宏把代碼包起來:
MJG_START_IGNORE_TOO_NEW
if ([cell respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)]) {
[cell setPreservesSuperviewLayoutMargins:NO];
}
if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
[cell setLayoutMargins:UIEdgeInsetsZero];
}
MJG_END_IGNORE_TOO_NEW
另外有一個叫做Faux Pas的代碼靜態(tài)分析工具,可以進(jìn)行API可用性的檢查犀被,但因為它的試用版隨機(jī)隱藏了檢查結(jié)果椅您,所以就沒再研究了。