开门见山,版本控制有以下两种时机:
- 预编译
- 运行时
预编译
在编译之前使用预编译指令来判断当前设备版本,不同版本执行不同的方法以便达到版本控制的目的。(iOS预编译指令)
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_5_0
// This code will compile on versions >= ios5.0
//这里面的代码在iOS5.0版本以上包括5.0才会编译
#else
// This code will compile on versions<5.0
//这里面的代码在iOS5.0版本以下才会编译
#endif
或者使用以下也OK
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
//xcode baseSDK为7.0或者以上
#else
//xcode baseSDK为7.0以下的
#endif
这是iOS定义了这个宏所以我们可以直接拿来做判断,后面只要把5改成相应的版本就行了。
运行时
运行的时候我们一般会用下面的这种方式获取系统版本来判断:
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
//设备系统为IOS 7.0或者以上的
}else{
//设备系统为IOS 7.0以下的
}
也可以用以下的方式:
if (@available(iOS 9.0, *)) {
// Fallback on this or after versions
} else {
// Fallback on earlier versions
}
过期警告:
当我们在使用API的过程中难免会碰到一些过期的API,那编译器在编译的时候就会报警告,即便你做了版本控制,但还是会有很烦人的警告出现,那怎么消除这种过期的API警告呢?
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
//此处写你过期API相关的代码
#pragma clang diagnostic pop
这样警告就消失了,那么也就不会那么烦心了,作为一个强迫症的我,很有必要!
扩展一:真机和模拟器宏
真机和模拟器的使用场景:
我们有时候会用到真机调试,比如说:用到摄像头.但是很多情况下我们不需要用真机,只需要模拟器就OK,所以为了避免在开发的过程中不会因为某些部分需要真机的功能而导致程序崩溃,我们就需要做真机和模拟器判断而执行不同代码。
苹果关于真机和模拟器有两个宏定义
- TARGET_IPHONE_SIMULATOR
- TARGET_OS_IPHONE
在真机sdk中位于iOS->usr/include/targetconditionals.h中,
在模拟器sdk中位于simulator->usr/include/targetconditionals.h中
仔细看其模拟器sdk中的定义:
#define TARGET_OS_IPHONE 1
#define TARGET_IPHONE_SIMULATOR 1
再来看真机sdk中的定义:
#define TARGET_OS_IPHONE 1
#define TARGET_IPHONE_SIMULATOR 0
可以发现两者的区别仅在于TARGET_IPHONE_SIMULATOR 的值,而TARGET_OS_IPHONE 则是一样,都是真。
所以,我们区分真机模拟器的时候务必用TARGET_IPHONE_SIMULATOR来判断,使用TARGET_OS_IPHONE将不会有效果。
PS: 一个有趣的现象(苹果的bug Or 坑?),关于区分真机和模拟器的预编译宏
做法举例如下:
我们开发过程中需要用到人脸识别,我们在 PCH(precompile prefix header) 文件中定义一个宏:
- 1、在真机的时候需要编译含有人脸识别的代码,定义这个宏
- 2、在模拟器的时候不需要编译含有人脸识别的代码,不定义该宏
#if TARGET_IPHONE_SIMULATOR
NSLog(@"运行在模拟器上");
//不定义FACE_RECOGNITION_CODE这个宏
#else
NSLog(@"运行在真机上");
//定义FACE_RECOGNITION_CODE这个宏
#define FACE_RECOGNITION_CODE
#endif
- 3、在具体代码中使用到的时候通过判断该宏是否有定义过该宏来执行人脸识别代码
#ifdef FACE_RECOGNITION_CODE
//书写人脸识别代码
#endif
PS:iOS判断真机还是模拟器的应用
扩展二:Xcode宏定义
Xcode在Build Setting里面就有一个是关于设定全局宏的,我们现在来解读一下:
我们在Build Setting里面输入"Preprocessor Macros"即可看到上面截图红框中的内容。
默认我们一创建工程的时候就会定义一个宏而且是Debug模式下才有的宏,就是"DEBUG=1",这个的意思是定义了一个宏,宏名为DEBUG,宏值为1,中间不能有空格(注意!!!)
那么我们就可以利用这个宏来做事情了,那么在利用的时候有以下两种写法:
#if DEBUG==1
//需要编译的代码
#endif
//或者加上空格
#ifdef DEBUG == 1
//需要编译的代码
#endif
#ifdef DEBUG
//需要编译的代码
#endif
那么在Build Setting处怎么添加自己定义的呢?
//方式一:宏名=宏值(只能是数字)
KODDEBUG=10
//方式二:宏名
KODDEBUG
注意:如果要加上宏值,等号前后都是不能加上空格的!!!
PS:PReprocessor Macros : 全局宏命令的应用
PS:关于Build Setting中的设置,请参考
Build settings reference
iOS开发之Build Setting设置
扩展三:调试输出日志
做法只需要在Build Setting的Release填上DEBUG_LOG这个字段即可,然后再在PCH文件上加上下面这一段
#ifndef __DEBUG_LOG__
#define NSLog(...) NSLog(__VA_ARGS__)
#else
#define NSLog(...) {}
#endif
或者利用默认的DEBUG=1这个来判断也是OK的,在PCH文件中加上:
#ifdef DEBUG
#define NSLog(...) NSLog(__VA_ARGS__)
#else
#define NSLog(...) {}
#endif
#if DEBUG == 1
#define NSLog(...) NSLog(__VA_ARGS__)
#else
#define NSLog(...) {}
#endif
iOS打印Debug日志的方式
扩展四:Build Setting设置
请详见iOS开发之Build Setting设置
参考
预处理命令简介
iOS编译期和运行时系统版本判断代码
一个有趣的现象(苹果的bug Or 坑?),关于区分真机和模拟器的预编译宏
iOS开发必备--环境变量配置(Debug & Release)
手把手教你给一个iOS app配置多个环境变量