【问题标题】:What are the common use cases for __IPHONE_OS_VERSION_MAX_ALLOWED?__IPHONE_OS_VERSION_MAX_ALLOWED 的常见用例是什么?
【发布时间】:2011-11-24 10:37:36
【问题描述】:

您会在哪些情况下使用 __IPHONE_OS_VERSION_MAX_ALLOWED 检查? __IPHONE_OS_VERSION_MIN_REQUIRED 呢?

【问题讨论】:

  • stackoverflow.com/questions/3269344/… 的可能重复项(请参阅我的答案)
  • 另外,你的意思是__IPHONE_OS_VERSION_MIN_REQUIRED,而不是MIN_ALLOWED。
  • 这不是重复的,其他线程问他们是什么意思,我的问题是问这些宏的常见用例(例如检查你运行的是iPhone还是iPad等)

标签: ios cocoa-touch


【解决方案1】:

了解这些是编译时常量很重要,因此它们对于在运行时检测您正在运行的平台或操作系统版本没有用处(例如,检测您是在 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 版本上运行的应用程序,并且能够利用每个平台的功能。

【讨论】:

  • 很好的答案。但是,如果您的目标是 iOS 3.1 或更高版本,则 NSClassFromString 已过时。您可能想使用if ([SomeClass class] != nil)。请参阅SDK Compatibility Guide。
  • 这个答案应该更新以反映新的@availability关键字:clang.llvm.org/docs/…
  • @bejado @availability 是否适用于编译时检查?像 adding this property 有条件地适用于
【解决方案2】:

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

+(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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-22
    • 2011-05-30
    • 1970-01-01
    • 2011-09-15
    • 2013-08-14
    • 2020-08-03
    • 2019-12-12
    • 1970-01-01
    相关资源
    最近更新 更多