1,让项目/Target支持不同版本的iOS
要让一个程序可以在多个版本的ios上运行相当简单:
-
在Project Settings中,将BaseSDK设置为最新的版本。
-
再将【iPhone OS Deployment Target】设置为最老的版本。
将上面这个版本信息设置正确非常简单。但是要在新的iOS上使用新的系统功能,而且还不能让程序在老版本的系统中崩溃,这相对难一些。
2,使用新iOS功能,同时支持老版本
如果你想在iOS4中启动一个后台任务,同时要支持老版本,就要像下面这样写:
| #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000 if ([[UIApplication sharedApplication] respondsToSelector:@selector(beginBackgroundTaskWithExpirationHandler:)]) { UIBackgroundTaskIdentifier bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{}]; // Perform work that should be allowed to continue in background [[UIApplication sharedApplication] endBackgroundTask:bgTask]; } #endif |
代码分为三个部分:
- #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000 这是编译时期的条件判断。如果我们选择的BaseSDK小于4.0,不会导致编译错误。
- UIApplication的beginBackgroundTaskWithExpirationHandler方法在运行时做的check。
- check中间的功能代码。
3,让条件判断更好看一些
上面代码有编译期判断和运行时check。要做两个判断,写法麻烦。我们要把两个check合并到一起:
|
IF_IOS4_OR_GREATER(
UIBackgroundTaskIdentifier
bgTask
=
[[UIApplication
sharedApplication]
beginBackgroundTaskWithExpirationHandler:^{}];
//
Perform work that should be allowed to continue in background
[[UIApplication
sharedApplication]
endBackgroundTask:bgTask];
);
|
可以像下面这样实现宏:
| #ifndef kCFCoreFoundationVersionNumber_iPhoneOS_4_0 #define kCFCoreFoundationVersionNumber_iPhoneOS_4_0 550.32 #endif #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000 #define IF_IOS4_OR_GREATER(...) \ if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iPhoneOS_4_0) \ { \ __VA_ARGS__ \ } #else #define IF_IOS4_OR_GREATER(...) #endif |
如果想要检查早于某一个sdk版本,可以像下面这样写:
|
#define IF_PRE_IOS4(...) \
if
(kCFCoreFoundationVersionNumber
<
kCFCoreFoundationVersionNumber_iPhoneOS_4_0)
\
{
\
__VA_ARGS__
\
}
|
关于上面写的宏:
-
这里使用的是kCFCoreFoundationVersionNumber在运行时判断iOS的版本。有很多例子用的是[[UIDevice currentDevice] systemVersion]。后者需要字符串比较,没有double型的比较直接。
-
没有使用do { x } while (0) ;来包装宏。
-
宏使用了变量参数列表,加多少个变量都没有关系,用逗号隔开就行。
再有一点,kCFCoreFoundationVersionNumber并不是所有版本SDK都有定义。有时候我们需要自己定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | #ifndef kCFCoreFoundationVersionNumber_iPhoneOS_2_0 #define kCFCoreFoundationVersionNumber_iPhoneOS_2_0 478.23 #endif #ifndef kCFCoreFoundationVersionNumber_iPhoneOS_2_1 #define kCFCoreFoundationVersionNumber_iPhoneOS_2_1 478.26 #endif #ifndef kCFCoreFoundationVersionNumber_iPhoneOS_2_2 #define kCFCoreFoundationVersionNumber_iPhoneOS_2_2 478.29 #endif #ifndef kCFCoreFoundationVersionNumber_iPhoneOS_3_0 #define kCFCoreFoundationVersionNumber_iPhoneOS_3_0 478.47 #endif #ifndef kCFCoreFoundationVersionNumber_iPhoneOS_3_1 #define kCFCoreFoundationVersionNumber_iPhoneOS_3_1 478.52 #endif #ifndef kCFCoreFoundationVersionNumber_iPhoneOS_3_2 #define kCFCoreFoundationVersionNumber_iPhoneOS_3_2 478.61 #endif #ifndef kCFCoreFoundationVersionNumber_iPhoneOS_4_0 #define kCFCoreFoundationVersionNumber_iPhoneOS_4_0 550.32 #endif |
4,更好的解决方案
比使用宏更好的方式是使用一个简单的函数。
比如下面的代码:
|
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 30200
if
([[UIDevice
currentDevice]
respondsToSelector:@selector(userInterfaceIdiom)]
&&
[[UIDevice
currentDevice]
userInterfaceIdiom]
==
UIUserInterfaceIdiomPad)
{
//
iPad specific layout changes
}
else
#endif
{
//
iPhone layout
}
|
可以使用IF_IOS4_OR_GREATER来改写,但更好的方法是下面的代码:
| if (isIPad()) { // iPad specific layout changes } else { // iPhone layout } |
关于isIPad()方法:
1
2
3
4
5
6
7
8
9
10
11
12
|
BOOL
isIPad()
{
IF_3_2_OR_GREATER
(
if
([[UIDevice
currentDevice]
userInterfaceIdiom]
==
UIUserInterfaceIdiomPad)
{
return
YES;
}
);
return
NO;
}
|
5,结论:
Apple没有让支持老版本的sdk非常简单。因为他们想让每个人一直使用新的系统,或者买新的设备。但这对开发人者来说很不现实,我们不能期待软件的用户一直使用新系统或新设备。
写适用多版本的程序关键点是写尽量少的if判断。你肯定不想为了对应多版本的问题,让自己的程序有很多的分支,因为每一个分支都意味着要进行测试。
如果你发现需要写很多的if判断,还可以为每个os版本写一个子类。用不同实现类实现功能。