宏定义是C语言提供的三种预处理功能的其中一种,这三种预处理包括:宏定义、文件包含、条件编译。
宏定义又称为宏代换、宏替换,简称“宏”。
预处理(预编译)工作也叫做宏展开:将宏名替换为字符串。 掌握”宏”概念的关键是“换”。一切以换为前提、做任何事情之前先要换,准确理解之前就要“换”。 即在对相关命令或语句的含义和功能作具体分析之前就要换:
例如:
#define Pi 3.1415926
把程序中出现的Pi全部换成3.1415926
其它的宏也是同理
注:宏是没有类型检测的 在使用的时候要注意宏的类型 比如说一个 数字的宏 你不能拿来当成NSString来使用
不带参数的宏,其实就是做一下简单替换
比如说: // 是否模拟器 #define isSimulator NSNotFound != [[[UIDevice currentDevice] model] rangeOfString:@”Simulator”].location
在代码中出现 isSimulator的地方都会替换成
NSNotFound != [[[UIDevice currentDevice] model] rangeOfString:@”Simulator”].location
这段代码 其实他的值是一个BOOL类型的
还有
#define PI 3.1415926
出现PI的地方那个都会会变成3.1415926
这个没什么要多余的,直接过了哒 =)
宏除了一般的字符串替换,还要做参数代换,这个是Macro Magic里面最具有魔法的点
#define ADD(a,b) a+b
在代码中出现
int total = ADD(2,3);
编译的时候就会替换成:int total = 2+3;
这里面有个坑,要跳过去
比如定义一个宏:#define S(r) r*r
代码中使用:S(a+b) 这个时候就会替换成 a+b*a+b 发现问题了吧
所以正确的宏应该是这样的:#define S(r) (r)*(r)
这个注意表达式的优先级别就可以绕过这个坑了。
这个用法个人感觉比较少见,但是确实很实用,比如定义一个准从相同协议
下面上一个例子看看 #define CreateClass(className)\ @interface className : NSObject\ -(void)sayHello;\ @end\ @implementation className\ -(void)sayHello \ {\ NSLog(@"Hello,%d",__LINE__);\ }\ @end\
CreateClass(ABC)
这样就定义了一个ABC的类 有木有很神奇?
在使用Block的时候 为了防止循环引用 需要变量弱引用 代码会比较麻烦
有了宏一切变得简单了 比如: #define WEAK_REF(obj) \ __weak typeof(obj) weak_##obj = obj; \
注:\ 在宏中是换行的意思,少了它换行会报错; ##是连接符号,将weak与obj这个参数连接成一个字符串
使用时:
WEAK_REF(abc);
Block中用:weak_abc即可
在Foundation中定义了一个宏叫 __LINE__ 这个宏是告诉你代码在第几行
你可以在任何一行代码打印__LINE__(NSLog(@”%d”,__LINE__))看看 是不是NSLog所在代码的行数?
这个大家可以想,如果做后台异常判断的时候把这个代码行数打出来,那不是很容易定位到问题所在地方?
类似__LINE__这个宏还有 __FILE__ __FUNCTION__
带参数的例子也讲的差不多了,其他的大家发动思维去做吧 =)
条件编译,也是一个魔法
最常用的就是各种环境 编译出不同的代码,不如一个URL 请求的测试环境和正式环境在开发和线上不是同一个,那一个宏 的条件编译就解决这个问题了
例子:
#ifdef ABC
URL = @”www”;
#else
URL = @”wwww”
#endif
在来一个例子:
NSLog问题,一般在线上上不需要打印出来,那通过宏也是可以控制的
在xxx.pch文件中加入
#ifdef __OPTIMIZE__ # define NSLog(…) {} #else # define NSLog(…) NSLog(__VA_ARGS__) #endif
出一个release版本的时候NSLog这个宏就没有任何作用
解释:
__OPTIMIZE__ 这个宏在release编译的时候Xcode会定义 把NSLog作为一个宏定义 __VA_ARGS__ 这个是一个可变参数宏#define 定义一个预处理宏 #undef 取消宏的定义 #include 包含文件命令 #include_next 与#include相似, 但它有着特殊的用途 #if 编译预处理中的条件命令, 相当于C语法中的if语句 #ifdef 判断某个宏是否被定义, 若已定义, 执行随后的语句 #ifndef 与#ifdef相反, 判断某个宏是否未被定义 #elif 若#if, #ifdef, #ifndef或前面的#elif条件不满足, 则执行#elif之后的语句, 相当于C语法中的else-if #else 与#if, #ifdef, #ifndef对应, 若这些条件不满足, 则执行#else之后的语句, 相当于C语法中的else #endif #if, #ifdef, #ifndef这些条件命令的结束标志. defined 与#if, #elif配合使用, 判断某个宏是否被定义 #line 标志该语句所在的行号 # 将宏参数替代为以参数值为内容的字符窜常量 ## 将两个相邻的标记(token)连接为一个单独的标记 #pragma 说明编译器信息 #warning 显示编译警告信息 #error 显示编译错误信息
好了,讲的比较乱,大家能用多少是多少吧
