Xcode 中关于"#"的小知识
在代码中使用Autolayout时,大家都会使用NSDictionaryOfVariableBindings这个宏,这个宏可以生成一个变量名到变量值映射的Dictionary。比如NSDictionaryOfVariableBindings(button1, button2)将会生成一个{ @"button1" = button1, @"button2 = button2 }的Dictionary。它是怎么做到的呢?我们来看看这个宏的定义:
#define NSDictionaryOfVariableBindings(...) _NSDictionaryOfVariableBindings(@"" # __VA_ARGS__, __VA_ARGS__, nil)
这个宏定义中有3个参数,后两个参数不难理解,但第一个参数中间有个#符号,语法上看起来比较怪异,这个是什么呢?以前在做越狱的mobilesubstrate开发时,其中定义的一堆宏频繁使用了这个符号,下面就来揭开#这个符号在宏定义中的迷雾。
预编译的一些知识
我们的代码在build时并不是直接进行编译的,在编译之前还进行了预编译处理。预编译会把include或import的文件导入到文件中,同时会将代码中用到的宏进行替换。注意宏是直接在代码中替换成宏的定义的,如果有嵌套也会逐层替换。
“#”指示一些预编译命令
预编译命令一般都是以#开头的,比如#include、#import、#if等,在这里就不一一说明了,本文主要说明一下#在宏定义里面的一些作用。
宏参数字符串化
在一个参数前加一个#,预处理时将会变成这个参数名的字符串常量,即字符串化(stringify)。比如:
#define GET_NAME(X) #X
int a = 0;
NSLog(@"%s",GET_NAME(a)); //output: "a"
NSLog(@"%s",GET_NAME(a+3)); //output: "a+3"
将会得到以下输出:
a
a+3
可以看出#,将参数原样转换成字符串常量,如果参数是一个表达式,那么输出这个表达式的原样字符串常量。
回头再看看NSDictionaryOfVariableBindings的定义:
#define NSDictionaryOfVariableBindings(...) _NSDictionaryOfVariableBindings(@"" # __VA_ARGS__, __VA_ARGS__, nil)
如果这样生成两个button的映射:
NSDictionaryOfVariableBindings(button1, button2);
那么预编译时就会转换成:
_NSDictionaryOfVariableBindings(@"""button1, button2", button1, button2, nil);
由于两个常量字符串放在一起就是字符串常量串联,将变成两个字符串常量组合在一起的字符串常量,也就是上面是一个空字符串""和"button1, button2"串联,所以上面的代码等价于:
_NSDictionaryOfVariableBindings(@"button1, button2", button1, button2, nil);
那么_NSDictionaryOfVariableBindings函数就可以将它的第一个参数按逗号,分割开作为key,后面就是各个key对应的值了。因此这段代码就创建了一个内容为{ @"button1" = button1, @"button2 = button2 }的Dictionary。
命名的串联
#在宏定义中的另一个作用就是用于命名的串联,用##就可以串联它左右两边的命名,比如以下代码:
#define CONCAT(X, Y) X ## Y
NSString *helloworld = @"Hello, world!";
NSLog(@"%@",CONCAT(hello, world)); //output: "Hello, world"
CONCAT(hello, world)实际被转换成helloworld。注意一下,因为宏是预编译阶段进行展开的,就是说在编译之前,因此代码中的hello和world即使没有定义其实也是没问题的,预编译处理后,这两个命名是不存在的。
可选可变参数
##在宏定义中可以放在__VA_ARGS__之前表示可变参数可以为空,否则的话可变参数至少为一个了。
#define MYLOG(format, ...) NSLog(format, ##__VA_ARGS__)
MYLOG(@"Don't make an error!");
上面代码中MLOG中只有一个参数,如果不加##,则MLOG至少需要两个参数,在Xcode里将会出现编译错误。
转自:http://blog.xcodev.com/blog/2013/12/16/mists-of-the-sharp/
Xcode 中关于"#"的小知识的更多相关文章
- HTML+CSS中的一些小知识
今天分享一些HTML.CSS的小知识,希望能够对大家有所帮助! 1.解决网页乱码的问题:最重要的是要保证各个环节的字符编码一致! (1)编辑器的编辑环境的字符集(默认字符集):Crtl+U 常见的编码 ...
- python中的一些小知识
在最近学习python中遇到的一些小问题汇总一下: 1.在windows7下安装python3.5版本时提示安装不了,缺少ServicePack1. 解决办法是,打开控制面板\系统和安全\Windo ...
- C语言中重要的小知识汇总
用于整理记录一些C语言下的小知识点: 1. 在C语言中,怎么查看一个数据类型占用了多少个字节大小呢? 可以使用sizeof(int)/sizeof(double)等来查看某数据类型到底用了几个字节: ...
- Android中的一些小知识
android中开发常用快捷键alt+/ 自动补全ctrl+1 有问题提示生成接收的参数 ctrl+L 在按2 注释// 注释 ctrl+//**/ 多行注释 ctrl+shift+/ android ...
- ASCLL码中的一些小知识
其次要记住asill值中 65是A 97是a A与a之间相隔32,用int转换后再用char转换回来. char b = s.charAt(i);为字符串转换成一个一个的.
- mysql中权限的小知识
参考:https://www.cnblogs.com/apollo1616/articles/10294490.html mysql中user表中host列的值的意义 % 匹配所有主机 localho ...
- Numpy中的一点小知识
train_set_x_orig, train_set_y, test_set_x_orig, test_set_y, classes = load_dataset()train_set_x_orig ...
- C++中的一些小知识
判断字符是否为数字 在C/C++中有isdigit()来判断一个字符是否为数字 原型:int isdigit(char c); 用法:#include <ctype.h> (C语言):#i ...
- java中方法传值小知识解析
1.java语言参数之间只有值传递,包括按值调用和按引用调用. 一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值. 按值调用:包括八大基本数据类型都是按值调用.传值的时候,也 ...
随机推荐
- Linux初学 - java环境安装
http://www.oracle.com/technetwork/java/javase/downloads/index.html 找到对应版本的jak的安装包 我这边下载的是64_rpm 下载完成 ...
- 虚拟机评估——如何确定一个CPU核上部署的虚拟机数量?
最近研究虚拟化技术,不可避免遇到一个问题:如何评估物理主机上虚拟主机的容量?下面这篇文章的思路有一定的启发性,转发一下. 如何确定一个CPU核上部署的虚拟机数量? 摘要:本文说明一个CPU核上部署虚拟 ...
- 【转】iOS 10 UserNotifications 使用说明
注意:XCode8的需要手动开启主target Capabilities中的Push Notification. 关于创建多个target后真机测试的证书问题,除了主target手动创建开发和发布证书 ...
- 流媒体选择Nginx是福还是祸?
CDN,视频云,已经“僧多粥少” 视频直播的持续升温,无意间也让带宽生意的争夺变得异常残酷.一时间,各种云计算.CDN.视频云提供商都在视频尤其是直播上投入重兵,揭竿而起的新生起义军们也正马不停蹄的赶 ...
- cocos2d-x.0创建工程
$ python create-multi-platform-projects.py -p PompaDroid -k cn.philon.pompadroid -l cpp
- SAP 系统管理内容
SAP 系统管理内容包含非常广泛,从底层硬件起到各种操作系统及各种系统软件及SAP软件组件等都会涉及到.SAP系统支持主流的IBM AIX.HP UNIX.Windows.Linux平台及Oracle ...
- ELK——为调试 Logstash Grok 表达式,安装 GrokDebuger 环境
内容 安装 RVM 安装 Ruby 和 Gems 安装 Rails 安装 jls-grok Ruby grok 解析 调试 grok 注意:不要用 root 执行以下操作. 用 logstash ...
- 转:简单的RTSP消息交互过程
简单的RTSP消息交互过程 C表示RTSP客户端,S表示RTSP服务端 1. 第一步:查询服务器端可用方法 1.C->S:OPTION request //询问S有哪些方法可用 ...
- jsp:forward response.sendRedirect
jsp中<jsp:forward page=""/>和response.sendRedirect("")两种跳转的区别 一.response.sen ...
- 服务器断电,Oracle数据库无法启动解决方案
数据库没有备份的情况下,数据库所在服务器由于意外断电,导致服务器启动之后,Oracle数据库startup报错. 1. 数据库没开归档模式 2. 无备份 解决方案: 1 2 3 4 5 6 7 8 9 ...