美文网首页iOS开发
在低版本iOS系统中调用高版本API

在低版本iOS系统中调用高版本API

作者: Cyyyyyyyy | 来源:发表于2016-08-03 22:04 被阅读1981次

    调用高版本API会有什么问题?

    在iOS7上,调用iOS8新加入的方法会导致崩溃。

    - (BOOL) findString:(NSString *)s inString:(NSString *)destString {
        NSString * lowDest = destString.lowercaseString;
        return [lowDest containsString:s];
    }
    

    NSStringcontainsString方法是在iOS8才被加入的,只要在iOS7上调用了containsString方法就会直接崩溃:

    在iOS7上初始化iOS8才有的对象会返回nil。虽然不会崩溃,但是可能会导致预料外的行为。

    LAContext* context = [[LAContext alloc] init];
    self.touchIDEnabled =
        [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
                             error:&error];
    

    LAContext是一个iOS8才加入的对象。在iOS7上,[[LAContext alloc] init]会返回nil。
    调用contextcanEvaluatePolicy:error:方法,依然返回nil。self.touchIDEnabled就被设置成了NO。
    按照代码逻辑,在iOS7上self.touchIDEnabled恰好就应该被设置为NO,在这个例子中不会有更严重的问题发生,但如果这个变量是self.touchIDDisabled,事情就不好说了。

    一定要用低版本系统不支持的API的时候该怎么办?

    iOS系统更新会带来新的接口和特性,我们总是会遇到不得不用新版本API的情况,所以代码中必须兼容新旧两种系统:

    • 通过判断iOS系统版本来兼容
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
        // Do something
    }
    
    • 在调用API前检查respondsToSelector
    if ([cell respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)]) {
        [cell setPreservesSuperviewLayoutMargins:NO];
    }
    
    
    • 在创建对象时判断[ClassName class]是否为nil
    - (BOOL)alertControllerAvailable {
        return [UIAlertController class] != nil; // iOS 8 and later.
    }
    

    从代码的可维护性来考虑,比较推荐后两种方式。

    检查API可用性的工具

    比较好的方案是用MJGAvailability.h在编译期检查。
    把MJGAvailability.h文件加入工程中,在预编译头文件最开头加上下面的代码即可:

    #define __IPHONE_OS_VERSION_SOFT_MAX_REQUIRED __IPHONE_7_0
    #import "MJGAvailability.h"
    

    其中的__IPHONE_7_0定义在Availability.h文件中,可以改成需要的任何系统版本。
    配置完成后,调用不可用的API会出现如下形式的警告:

    xxxxxxx.m:64:18: 'containsString:' is deprecated: TOO NEW!
    

    如果配置后编译没有生效,把Build Settings里面的Enable Modules (C and Objective-C)项改为NO试试,具体原因我还不知道是为什么。

    这个工具无法检查出我们的代码有没有进行过版本兼容处理,它会对所有有问题的代码报错。所以我们要在处理过兼容性的地方,显式的用宏把代码包起来:

    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的代码静态分析工具,可以进行API可用性的检查,但因为它的试用版随机隐藏了检查结果,所以就没再研究了。

    相关文章

      网友评论

      • WKCaesar:MJGAvailability.h 之前在xcode8 中可以用, 但是在xcode9里面就报错

      本文标题:在低版本iOS系统中调用高版本API

      本文链接:https://www.haomeiwen.com/subject/jdqcsttx.html