Objective-C Type Encodings
转自:nshipster,觉得再某些场景上有点用,就直接抄过来了。
@encode,@编译器指令 之一,返回一个给定类型编码为一种内部表示的字符串(例如,@encode(int) → i),类似于 ANSI C 的 typeof 操作。苹果的 Objective-C 运行时库内部利用类型编码帮助加快消息分发。
这里有一个所有不同的 Objective-C 类型编码的概要:
Objective-C Type Encodings
编码 | 意义 |
---|---|
c |
A char |
i |
An int |
s |
A short |
l |
A longl is treated as a 32-bit quantity on 64-bit programs. |
q |
A long long |
C |
An unsigned char |
I |
An unsigned int |
S |
An unsigned short |
L |
An unsigned long |
Q |
An unsigned long long |
f |
A float |
d |
A double |
B |
A C++ bool or a C99 _Bool |
v |
A void |
* |
A character string (char *) |
@ |
An object (whether statically typed or typed id) |
# |
A class object (Class) |
: |
A method selector ( SEL) |
[*array type*] |
An array |
{*name=type...*} |
A structure |
(*name*=*type...*) |
A union |
bnum |
A bit field of *num* bits |
^type |
A pointer to type |
? |
An unknown type (among other things, this code is used for function pointers) |
当然,用图表很不错,但是用代码实践更好:
|
|
结果:
类型 | 编码 |
---|---|
int |
i |
float |
f |
float * |
^f |
char |
c |
char * |
* |
BOOL |
c |
void |
v |
void * |
^v |
NSObject * |
@ |
NSObject |
# |
[NSObject] |
{NSObject=#} |
NSError ** |
^@ |
int[] |
[5i] |
float[] |
[3f] |
struct |
{_struct=sqQ} |
这里有一些特别需要注意的:
- 指针的标准编码是加一个前置的
^
,而char *
拥有自己的编码*
。这在概念上是很好理解的,因为 C 的字符串被认为是一个实体,而不是指针。 BOOL
是c
,而不是某些人以为的i
。原因是char
比int
小,且在 80 年代 Objective-C 最开始设计的时候,每一个 bit 位都比今天的要值钱(就像美元一样)。BOOL
更确切地说是signed char
(即使设置了-funsigned-char
参数),以在不同编译器之间保持一致,因为char
可以是signed
或者unsigned
。- 直接传入
NSObject
将产生#
。但是传入[NSObject class]
产生一个名为NSObject
只有一个类字段的结构体。很明显,那就是isa
字段,所有的NSObject
实例都用它来表示自己的类型。
方法编码
如苹果的 “Objective-C Runtime Programming Guide” 中所提到的,有一大把内部使用的类型编码无法用 @encode()
返回。
以下是协议中声明的方法的类型修饰符:
Objective-C Method Encodings
编码 | 意义 |
---|---|
r |
const |
n |
in |
N |
inout |
o |
out |
O |
bycopy |
R |
byref |
V |
oneway |
对于那些熟悉 NSDistantObject 的人,你无疑会认出这些是 Distributed Objects 的残留。
尽管 DO (Distributed Objects) 在 iOS 时代已经不那么时髦了,它仍是用于 Cocoa 应用程序进程间通信的协议————甚至用于网络上的不同机器之间。在这些约束下,上下文里附加的内容就带来了很多好处。
例如,分页式的对象消息的参数默认是用代理传递的。在那些没必要用到低效的代理的情况下,增加一个 bycopy
修饰符以保证发送了一份完整的拷贝。同样,默认情况下,带用 inout
的参数表明它在发消息时对象即可传入又可传出。将参数特别标注为 in
或 out
,程序将避免一些来回的开销。
我们从对 Objective-C 的类型编码的全新理解上能得到什么呢? 不瞒您说,其实没多少(除非你在做一些疯狂的元编程)。
但是就如我们最开始所说的,在追求破译密文的过程中要用到不少智慧。
看看类型编码为我们展现的有关 Objective-C 内部的细节,这本身就是一种高尚的追求。如果刨根问到底的话,我们需要了解一下 Distributed Objects 神秘的历史以及那 至今仍然存在 的复杂的参数修饰符。