__IPHONE_OS_VERSION_MAX_ALLOWED有哪些常见用例?

时间:2011-09-24 22:59:29

标签: ios cocoa-touch

您将使用__IPHONE_OS_VERSION_MAX_ALLOWED支票的情况是什么?那么__IPHONE_OS_VERSION_MIN_REQUIRED呢?

2 个答案:

答案 0 :(得分:56)

重要的是要理解这些是编译时常量,因此它们对于在运行时检测您正在运行的平台或操作系统版本没有用(例如,检测您是否在iPad上运行iPhone)。

这些常量的作用是允许您在编译时检测是否为给定的SDK或部署目标构建代码。例如,如果您编写的开源库包含仅在针对iOS 5 SDK编译时才有效的代码,则可以包含此检查以检测编译代码的SDK:

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 50000
    //you can use iOS 5 APIs here because the SDK supports them
    //but the code may still crash if run on an iOS 4 device
#else
    //this code can't use iOS 5 APIs as the SDK version doesn't support them
#endif

或者,如果您想查看目标的最低操作系统版本是什么......

#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000
    //minimum deployment target is 5.0, so it's safe to use iOS 5-only code
#else
    //you can use iOS5 APIs, but the code will need to be backwards
    //compatible or it will crash when run on an iOS 4 device
#endif

这与在运行时检测您正在运行的操作系统不同。如果您使用iOS 4 SDK在上面的第一个示例中编译代码,它将使用您的iOS 4安全代码,但在iOS 5设备上运行时不会利用任何iOS 5功能。如果您使用iOS 5 SDK构建它,然后将部署目标设置为iOS 4并尝试在iOS 4设备上运行它,它将编译并安装正常但仍可能在运行时崩溃,因为iOS 5 API不存在。

在上面的第二个示例中,如果您将部署目标设置为iOS 4或更低版本,那么它将使用iOS 4安全代码路径,但如果您将部署目标设置为iOS 5,则它将无法运行在iOS 4设备上(它将拒绝安装)。

要构建在iOS 4和5上运行的应用程序,并且仍然能够利用iOS 5功能(如果可用),则需要执行运行时检测。要在运行时检测iOS版本,您可以执行以下操作:

if ([[[UIDevice currentDevice] systemVersion] compare:@"5.0.1" options:NSNumericSearch] != NSOrderedAscending) {
    //running on iOS 5.0.1 or higher
}

但这意味着要准确跟踪在哪个操作系统版本中添加了哪些API功能,这些功能很笨重,只能作为最后的手段来完成。通常,更好的方法是使用特征检测,如下所示:

if ([SomeClass class]) {
    //this class exists
}

if ([SomeClass instancesRespondToSelector:@selector(someMethod:)]) {
    //this method exists
}

此外,要在运行时检测您是否在iPad或iPhone上,可以执行以下操作:

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
    //on an ipad
}

在运行时执行这些检查可以创建一个在多个设备和iOS版本上运行的应用程序,并且能够利用每个平台的功能。

答案 1 :(得分:0)

使用 instancesRespondToSelector:的实际实现/示例,扩展@Nick Lockwood的anwser:

+(BOOL) testIsHeaderInConnectData:(NSData *) connectData {
    static NSString *headString = nil;
    static NSData *headData = nil;
    static BOOL rangeCheckOk = NO;
    static BOOL rangeCheckTestComplete = NO;
    if (!rangeCheckTestComplete) {
        rangeCheckOk = [NSData instancesRespondToSelector:@selector(rangeOfData:options:range:)]; 
        headString = @"HEAD ";
        headData = (rangeCheckOk?[[NSData alloc] initWithBytes:headString.UTF8String length:headString.length]:nil);
        headString = (rangeCheckOk?nil:[[NSString alloc ]initWithString:headString]);
        rangeCheckTestComplete = YES;
    }

    NSInteger testLength = connectData.length;
    BOOL isHeader = testLength > 5;
    if (isHeader) {
        testLength = (testLength < 128?testLength:128);
        if (rangeCheckOk) {
             isHeader = [connectData rangeOfData:headData options:0 range:(NSRange){0,testLength}].location!=NSNotFound;
        } else {
            NSString *headStart = [[NSString alloc] initWithBytes:connectData.bytes length:testLength encoding:NSUTF8StringEncoding];
            isHeader = [headStart rangeOfString:headString].location!=NSNotFound;
            [headStart release];
        }
    }
    return isHeader;
}