runtime programming guide
这次准备好好研究下runtime programming, 先从encodings开始了解,这个对于理解oc的类也是很有帮助的。
废话不多说直接开始。
Type Encodings
compiler 编码encode 每个method的返回值,参数类型,将这些信息保存在一个字符串里。然后将这个string和selector关联起来。
这套编码也适用于其他场景,所以这个@encode编译器指令是设计成公开的。当给定一个type的规范声明,@encode()返回相对应的字符串类型编码值。
char *buf1 = @encode(int **);
char *buf2 = @encode(struct key);
char *buf3 = @encode(Rectangle);
数组的type code是一个中括号里面,然后紧接着一个数组个数值和相对应的数组元素的类型,如一个包含12个float指针的数组的编码为:[12^f]
structures 是一个大括号里,里面是显示紧跟着structure tag(struct的结构名称)然后一个等号(equal sign)=,接着就是struct里各个类型排列在一起,比如
typedef struct example {
id anObject;
char *aString;
int anInt;
} Example;
的type code值为 {example=@*i}
, 如果是一个结构体的指针,那么encode为^{example=@*i}
,如果是一个结构体的指针的指针,则是^^{example}
.
Objects对象也被看成一个struct。@encode(NSObject)结果是{NSObject=#}
, 因为NSObject class里就一个isa(class 类型)的变量。
尽管 @encode()不直接返回数据, 但运行时会使用额外的一个encoding列表来表示一些方法声明的后缀修饰符.
code | Meaning |
---|---|
r | const |
i | int |
N | inout |
o | out |
O | bycopy |
R | byref |
V | oneway |
Declared Propertyies
当编译器碰到property声明时,它会生成描述性的带有关于class, category或者protocol的metadata元数据。
你能通过一些列的api函数来访问这个metadata,通过class,protocol上的name来查找property。可以通过@encode来获取property的encode string。可以copy property的attributes list(C strings)。
class和protocol都有一个properties list的值。
property type and functions
可以通过class_copyPropertyList和protocol_copyPropertyList来遍历class(包括loaded categories)和protocol的property list
通过property_getAttributes可以获取到一个property属性的@encode type的值。
比如一个@property (nonatomic, strong) NSString *login;的property @encode值为T@"NSString",&,N,V_login
每个逗号都是分割一个属性attribute,实际上当你获取到objc_property_attribute_t *attrs = property_copyAttributeList(prot, &outcount);(注意你还需要主动free掉attrs)
outcount的值就是分割后的数组的个数。
attrs分别为:
property index | name | value |
---|---|---|
0 | T | @"NSString" |
1 | & | |
2 | N | |
3 | V | _login |
Property type string
文档里面有一段英文很重要,他描述了property type的string值的格式(这个值可以通过@encode或者通过property_getAttributes来获取)。
You can use the property_getAttributes function to discover the name, the @encode type string of a property, and other attributes of the property.
The string starts with a T followed by the @encode type and a comma, and
finishes with a V followed by the name of the backing instance variable.
Between these, the attributes are specified by the following descriptors, separated by commas:
*** 这段英文很重要,说明了格式,首先是以一个T开头的,然后@encode type加一个逗号,以一个V后面带上存储支持的实例变量,然后在中间,每个attributes都是以逗号隔开的,这些attributes描述如下:***
可以官场上面的那个例子@property (nonatomic, strong) NSString *login;的property @encode值为T@"NSString",&,N,V_login
Table 7-1 Declared property type encodings
Code | Meaning |
---|---|
R | The property is read-only (readonly). |
C | The property is a copy of the value last assigned (copy). |
& | The property is a reference to the value last assigned (retain). |
N | The property is non-atomic (nonatomic). |
G<name> | The property defines a custom getter selector name. The name follows the G (for example, GcustomGetter,). |
S<name> | The property defines a custom setter selector name. The name follows the S (for example, ScustomSetter:,) |
D | The property is dynamic (@dynamic). |
W | The property is a weak reference (__weak). |
P | The property is eligible for garbage collection. |
t<encoding> | Specifies the type using old-style encoding. |
这个链接里有相关的demo示例说明property declaration声明和描述description。
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html#//apple_ref/doc/uid/TP40008048-CH101-SW5
这里只罗列少数几个:
property declaration | description |
---|---|
@property(getter=intGetFoo, setter=intSetFoo:) int intSetterGetter; | Ti,GintGetFoo,SintSetFoo:,V_intSetterGetter |
@property int intSynthEquals;In the implementation block:@synthesize intSynthEquals=_intSynthEquals; | Ti,V_intSynthEquals |
@property int (*functionPointerDefault)(char *); | T^?,V_functionPointerDefault |
@property (strong, atomic) NSString * dataObject; | T@"NSString",&,V_dataObject |
function/method type encode
先看例子:
//- (void)viewWillAppear:(BOOL)animated -> v20@0:8B16
NSLog(@"%s", class_getInstanceMethod([self class], @selector(viewWillAppear:)));
//- (void) setSomething:(id) anObject -> v24@0:8@16
NSLog(@"%s", method_getTypeEncoding(class_getInstanceMethod([self class], @selector(setSomething:))));
//- (BOOL) setSomething:(UInt8)animated aa:(id)anObject -> B28@0:8C16@20
NSLog(@"%s", method_getTypeEncoding(class_getInstanceMethod([self class], @selector(setSomething:aa:))));
//- (BOOL) setSomething:(UInt16)animated aa:(id)anObject -> B28@0:8s16@20
NSLog(@"%s", method_getTypeEncoding(class_getInstanceMethod([self class], @selector(setSomething:aa:))));
//- (BOOL) setSomething:(int)animated aa:(id)anObject -> B28@0:8i16@20
NSLog(@"%s", method_getTypeEncoding(class_getInstanceMethod([self class], @selector(setSomething:aa:))));
//- (BOOL) setSomething:(long)animated aa:(id)anObject-> B32@0:8q16@24
NSLog(@"%s", method_getTypeEncoding(class_getInstanceMethod([self class], @selector(setSomething:aa:))));
typedef struct {
uint32_t a;
uint16_t b;
uint8_t c;
} __attribute__((packed)) MyStruct;
// - (void)strutMethod:(MyStruct)aa -> v23@0:8{?=ISC}16
NSLog(@"%s", method_getTypeEncoding(class_getInstanceMethod([self class], @selector(strutMethod:))));
那么如何理解呢?
- v means void return type
- 20 means the size of the argument frame (20 bytes),整个方法参数占位的总长度
- @0 means that there is an Objective-C object type at byte offset 0 of the argument frame (this is the implicit self object in each Objective-C method),这个表示在offset为0的地方有一个objective-c的对象,在objective-c method里,首个对象是self自身。
- :8 means that there is a selector at byte offset 8 (this is the implicit _cmd in every method, which is the selector that was used to invoke the method). 在offset为8的地方有一个SEL,由于我测试的是64位机器上,所以之前的OC的对象指针占位8个字节。
- B16 means 在offset 16的地方,有一个bool类型的参数,由于oc的对象和sel都是指针类型,64位机下所以都是占位8位,这里的bool也就出现在offset16的地方了。至于为什么bool参数占位了4个字节。主要原因是内存对齐的原因
从上面看起来,不管是bool,uint8,uint16,int都被认为4个字节。因为他们的内存实际占位都小于4个字节,由于内存对齐原因所以实际最后占位为4字节。这里当你看最后一个MyStruct就可以看出,当主动告诉编译器取消结构体的内存对齐,就发现最后一个参数事迹展位是7(4+2+1)个字节
注:packed属性:使用该属性可以使得变量或者结构体成员使用最小的对齐方式,即对变量是一字节对齐,对域(field)是位对齐.
typedef struct {
uint32_t a;
uint16_t b;
uint8_t c;
} __attribute__((packed)) MyStruct;
未完待续
至此先了解介绍完了关于type encodings, property type encodings,method encodings。稍后继续补充了解更多的运行时编程相关的知识点,runtime programming guide~~~.