ios版本判断

本篇译自:Matt Gallagher的blog-http://cocoawithlove.com
原文:http://cocoawithlove.com/2010/07/tips-tricks-for-conditional-ios3-ios32.html
这篇日志会告诉你在ios编程中如何判断不同的版本的ios系统。
1,让项目/Target支持不同版本的iOS
要让一个程序可以在多个版本的ios上运行相当简单:

  • 在Project Settings中,将BaseSDK设置为最新的版本。
  • 再将【iPhone OS Deployment Target】设置为最老的版本。

将上面这个版本信息设置正确非常简单。但是要在新的iOS上使用新的系统功能,而且还不能让程序在老版本的系统中崩溃,这相对难一些。

2,使用新iOS功能,同时支持老版本
如果你想在iOS4中启动一个后台任务,同时要支持老版本,就要像下面这样写:
Objective-C

[cpp] view plaincopy
 
 
  1. #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000  
  2.    if ([[UIApplication sharedApplication]  
  3.        respondsToSelector:@selector(beginBackgroundTaskWithExpirationHandler:)])  
  4.    {  
  5.        UIBackgroundTaskIdentifier bgTask = [[UIApplication sharedApplication]  
  6.        beginBackgroundTaskWithExpirationHandler:^{}];  
  7.   
  8.        // Perform work that should be allowed to continue in background  
  9.        [[UIApplication sharedApplication] endBackgroundTask:bgTask];  
  10.     }  
  11. #endif  

代码分为三个部分:

  1. #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000 这是编译时期的条件判断。如果我们选择的BaseSDK小于4.0,不会导致编译错误。
  2. UIApplication的beginBackgroundTaskWithExpirationHandler方法在运行时做的check。
  3. check中间的功能代码。

3,让条件判断更好看一些
上面代码有编译期判断和运行时check。要做两个判断,写法麻烦。我们要把两个check合并到一起:
Objective-C

[cpp] view plaincopy
 
 
  1. IF_IOS4_OR_GREATER(  
  2.    UIBackgroundTaskIdentifier bgTask = [[UIApplication sharedApplication]  
  3.        beginBackgroundTaskWithExpirationHandler:^{}];  
  4.    // Perform work that should be allowed to continue in background  
  5.    [[UIApplication sharedApplication] endBackgroundTask:bgTask];  
  6. );  

可以像下面这样实现宏:
Objective-C

[cpp] view plaincopy
 
 
  1. #ifndef kCFCoreFoundationVersionNumber_iPhoneOS_4_0  
  2. #define kCFCoreFoundationVersionNumber_iPhoneOS_4_0 550.32   
  3. #endif  
  4. #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000  
  5. #define IF_IOS4_OR_GREATER(...) \  
  6.   if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iPhoneOS_4_0) \   
  7.   { \  
  8.       __VA_ARGS__ \  
  9.   }  
  10. #else  
  11. #define IF_IOS4_OR_GREATER(...)  
  12. #endif  

如果想要检查早于某一个sdk版本,可以像下面这样写:
Objective-C

[cpp] view plaincopy
 
 
  1. #define IF_PRE_IOS4(...) \  
  2.   if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iPhoneOS_4_0) \   
  3.   { \  
  4.       __VA_ARGS__ \  
  5.   }  

关于上面写的宏:

  1. 这里使用的是kCFCoreFoundationVersionNumber在运行时判断iOS的版本。有很多例子用的是[[UIDevice currentDevice] systemVersion]。后者需要字符串比较,没有double型的比较直接。
  2. 没有使用do { x } while (0) ;来包装宏。
  3. 宏使用了变量参数列表,加多少个变量都没有关系,用逗号隔开就行。

再有一点,kCFCoreFoundationVersionNumber并不是所有版本SDK都有定义。有时候我们需要自己定义:
Objective-C

[cpp] view plaincopy
 
 
  1. #ifndef kCFCoreFoundationVersionNumber_iPhoneOS_2_0  
  2. #define kCFCoreFoundationVersionNumber_iPhoneOS_2_0 478.23   
  3. #endif  
  4. #ifndef kCFCoreFoundationVersionNumber_iPhoneOS_2_1  
  5. #define kCFCoreFoundationVersionNumber_iPhoneOS_2_1 478.26   
  6. #endif  
  7. #ifndef kCFCoreFoundationVersionNumber_iPhoneOS_2_2  
  8. #define kCFCoreFoundationVersionNumber_iPhoneOS_2_2 478.29   
  9. #endif  
  10. #ifndef kCFCoreFoundationVersionNumber_iPhoneOS_3_0  
  11. #define kCFCoreFoundationVersionNumber_iPhoneOS_3_0 478.47   
  12. #endif  
  13. #ifndef kCFCoreFoundationVersionNumber_iPhoneOS_3_1  
  14. #define kCFCoreFoundationVersionNumber_iPhoneOS_3_1 478.52   
  15. #endif  
  16. #ifndef kCFCoreFoundationVersionNumber_iPhoneOS_3_2  
  17. #define kCFCoreFoundationVersionNumber_iPhoneOS_3_2 478.61   
  18. #endif  
  19. #ifndef kCFCoreFoundationVersionNumber_iPhoneOS_4_0  
  20. #define kCFCoreFoundationVersionNumber_iPhoneOS_4_0 550.32   
  21. #endif  

4,更好的解决方案
比使用宏更好的方式是使用一个简单的函数。
比如下面的代码:
Objective-C

[cpp] view plaincopy
 
 
  1. #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 30200  
  2.   if ([[UIDevice currentDevice] respondsToSelector:@selector(userInterfaceIdiom)] &&   
  3.       [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)   
  4.   {  
  5.       // iPad specific layout changes  
  6.   }  
  7.   else  
  8. #endif  
  9.   {  
  10.       // iPhone layout  
  11.   }  

可以使用IF_IOS4_OR_GREATER来改写,但更好的方法是下面的代码:
Objective-C

[cpp] view plaincopy
 
 
  1. if (isIPad())  
  2. {  
  3.   // iPad specific layout changes  
  4. }  
  5. else  
  6. {  
  7.   // iPhone layout  
  8. }  

关于isIPad()方法:
Objective-C

[cpp] view plaincopy
 
 
  1. BOOL isIPad()  
  2. {  
  3.   IF_3_2_OR_GREATER  
  4.   (  
  5.       if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)   
  6.       {  
  7.           return YES;  
  8.       }  
  9.   );  
  10.       
  11.   return NO;  
  12. }  

5,结论:
Apple没有让支持老版本的sdk非常简单。因为他们想让每个人一直使用新的系统,或者买新的设备。但这对开发人者来说很不现实,我们不能期待软件的用户一直使用新系统或新设备。
写适用多版本的程序关键点是写尽量少的if判断。你肯定不想为了对应多版本的问题,让自己的程序有很多的分支,因为每一个分支都意味着要进行测试。
如果你发现需要写很多的if判断,还可以为每个os版本写一个子类。用不同实现类实现功能。

[cpp] view plaincopy
 
 
  1. #ifdef __MAC_OS_X_VERSION_MAX_ALLOWED  
  2. // code only compiled when targeting Mac OS X and not iOS  
  3. // note use of 1050 instead of __MAC_10_5  
  4. #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050  
  5. if (CGColorCreateGenericCMYK != NULL) {  
  6. CGColorCreateGenericCMYK(0.1,0.5.0.0,1.0,0.1);} else {  
  7. #endif  
  8. // code to create a color object with earlier technology  
  9. #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050  
  10. }  
  11. #endif  
  12. #endif  
  13. }  

相关推荐