说说 Objective-C 里的 @()

转载 2015年07月10日 18:22:53

Intro

在 Objective-C 中我们可以用 @"foo" 来创建一个 NSString 常量,看起来似乎平淡无奇。

但它背后其实比想象的精彩,@ 可以被理解成一个特殊的宏,其接受一个 C 字符串作为参数,也可写作 @("foo")

之所以说 @ 是一个特殊的宏,是因为其能根据传入的 C 字符串类型不同——C 字符串常量或 C 字符串——在运行时构建返回不同类型的 NSString,参见下面的代码:

1
2
3
4
5
6
7
8
char* obtain_c_string(void)
{
  return "c_string";
}

NSLog(@"%@", @"foo".class);
NSLog(@"%@", @("bar").class);
NSLog(@"%@", @(obtain_c_string()).class);

输出结果如下:

1
2
3
2013-06-05 01:14:15.097 Sandbox[45804:c07] __NSCFConstantString
2013-06-05 01:14:15.098 Sandbox[45804:c07] __NSCFConstantString
2013-06-05 01:14:15.098 Sandbox[45804:c07] __NSCFString

可见,如果传入的是 C 字符串常量,运行时构建的则为 NSConstantString;如果传入的是 C 字符串则创建的是 NSString

Then?

你可能会问这么理解了又怎样?

众所周知,Objective-C 代码里有很多地方需要我们把代码中的一些文法串写成字符串再作为传入参数,比如 KVO 中的 keyPath 参数往往就要传入形如 propertyA.propertyB 的字符串,从实用角度出发这有两个弊端:

  • 写字符串的时候没有代码提示,很容易写错
  • 即便一开始写对了,如果后来相关类重构了,keyPath 的参数便失效了,而 Xcode Refactor 无法扫描字符串

当我们理解了 @(),再加上自定义的宏,上述两个问题便可迎刃而解。

1
2
3
4
5
6
7
8
9
/**
 * # 将宏的参数字符串化,C 函数 strchr 返回字符串中第一个 '.' 字符的位置
 */
#define Keypath(keypath) (strchr(#keypath, '.') + 1)

[objA addObserver:objB
       forKeyPath:@Keypath(ObjA.property1.property2) // 有代码提示,可以被重构扫描到
          options:nil
          context:nil];

这个简单实现只算是抛砖引玉,除了 @() 配合自定义宏来字符串化代码中的文法串,更多的用法就有待在开发中不断发掘了。

PS: 在即将完成这篇文章的时候我发现已有国外开发者利用 @() 特性配合自定义宏,全面系统的解决了上述问题,详情参见 libextobjc/EXTKeyPathCoding.h

Extra

此外,@() 还可以接受 int 字面量或 int 变量作为参数,有兴趣的读者可以自行感受下。

转自:http://dlog.dismory.com/blog/2013/06/06/talk-about-the-%40-in-objective-c/

iOS面试试题(一)

#import 跟#include 又什么区别,@class呢, #import 跟 #import””又什么区别? #import是Objective-C导入头文件的关键字,#include是C/C...
  • IT_DS
  • IT_DS
  • 2016年03月12日 20:23
  • 665

说说 Objective-C 里的 @()字面量语法

http://www.cocoachina.com/ios/20141218/10688.html 在 Objective-C 中我们可以用 @"foo" 来创建一个 NSStrin...
  • ssyyjj88
  • ssyyjj88
  • 2016年04月23日 12:11
  • 175

说说Java里的equals(上)

转载自:https://zhuanlan.zhihu.com/p/27573287 Java字符串两种声明方式在堆内存中不同的体现,我们在写代码过程中,为了避免重复的创建对象,尽量使用Str...
  • ZcBarry
  • ZcBarry
  • 2017年07月03日 10:05
  • 233

说说Unity3D里的各种坐标系

今天博主想和大家聊聊unity3D中各种坐标系。自从Unity4.6版本推出uGUI后,unity3d坐标系的大家庭中便增加了RectTransform这个新成员,如果你不想被各种坐标系搞得晕头转向的...
  • KingSea168
  • KingSea168
  • 2015年11月03日 08:27
  • 4775

说说Unity3D里的各种坐标系

各位朋友大家好,欢迎大家关注我的博客,我是秦元培,我的博客地址是http://qinyuanpei.com。今天博主想和大家聊聊unity3D中各种坐标系。自从Unity4.6版本推出uGUI后,un...
  • ykr168age
  • ykr168age
  • 2015年10月28日 13:54
  • 727

说说Java里的equals(上)

在Java字符串那些事儿一文发表后,朋友给我留言说:比较字符串用equals不就完了呗,干嘛要用"==",吃饱了撑的,能不能来点实际的。其实在文章里我是想表明,Java字符串两种声明方式在堆内存中不同...
  • qqtingshuo
  • qqtingshuo
  • 2017年11月17日 11:01
  • 43

对java反射机制的一些理解

1.什么是java的反射机制? 说实话,一开始的时候我真的不知道什么是java的反射机制,反射机制又有什么用呢?甚至于在刚开始的时候,我还觉得java反射机制真的麻烦,还不如平常的使用类以及其实例对...
  • YQYnsmile
  • YQYnsmile
  • 2016年08月14日 10:47
  • 2002

Objective-c - block作为函数的参数

/* Objective-c - block作为函数的参数       1> block做为一种数据类型,可以做为方法或者函数的参数.       2> 将b...
  • xuezhangjun0121
  • xuezhangjun0121
  • 2017年01月11日 21:18
  • 510

Objective-C - 继承的经典实例

继承/* 1.继承的好处: 1> 抽取重复代码 2> 建立了类之间的关系 3> 子类可以拥有父类中的所有成员变量和方法 2.注意点 1> 基本上所有类的根类是NSObject */ /**...
  • wangzi11322
  • wangzi11322
  • 2015年04月18日 13:01
  • 1094

Android 之实现类似QQ图片说说照片选择

Android 之实现类似QQ图片说说照片选择转载请注明出处:http://blog.csdn.net/klxh2009/ 本文出自【付小华的博客】 效果展示 布局文件 代码实现 效果展示 布局文件...
  • klxh2009
  • klxh2009
  • 2016年04月26日 22:12
  • 3813
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:说说 Objective-C 里的 @()
举报原因:
原因补充:

(最多只允许输入30个字)