重识 Objective-C Runtime - 看透 Type 与 Value
method TypeEncoding
规则很简单:
- (void)foo; => "v@:" // 'v':void; '@':self; ':':selector
- (int)barWithBaz:(double)baz; => "i@:d" // 'i':int; '@':self; ':':selector
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section; => "i@:@i" // 'i':int; '@':self; ':':selector; '@':tableview; 'i':section;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; => "@@:@@" // '@':UITableViewCell; '@':self; '@':tableview; '@':indexPath;
类与对象
Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理。
跟其他静态语言还有这区别,有例子吗?
类与对象基础数据结构
Class
Objective-C类是由Class类型来表示的,它是一个指向objc_class结构体的指针。它的定义如下:
typedef struct objc_class *Class
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE; // 父类
const char *name OBJC2_UNAVAILABLE; // 类名
long version OBJC2_UNAVAILABLE; // 类的版本信息,默认为0
long info OBJC2_UNAVAILABLE; // 类信息,供运行期使用的一些位标识
long instance_size OBJC2_UNAVAILABLE; // 该类的实例变量大小
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 该类的成员变量链表
struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法定义的链表
struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法缓存
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 协议链表
#endif
} OBJC2_UNAVAILABLE;
经常提到的isa,原来就是Class,比如NSError * error,[error class]的isa指针,指向的是NSError
所有的类自身也是一个对象,只是类的结构里面的isa,指向的是metaClass(元类)
例子
NSError *error = [[NSError alloc] init];
NSLog(@"This objcet is %p", error);
NSLog(@"Class is %@, super class is %@", [error class], [error superclass]);
Class currentClass = [error class];
for (int i = 0; i < 4; i++) {
NSLog(@"Following the isa pointer %d times gives %p", i, currentClass);
currentClass = objc_getClass((__bridge void *)currentClass);
}
NSLog(@"NSObject's class is %p", [NSObject class]);
NSLog(@"NSObject's meta class is %p", objc_getClass((__bridge void *)[NSObject class]));
// console
2019-02-01 15:32:05.494550+0800 Test[43425:193320] This objcet is 0x100707980
2019-02-01 15:32:05.494656+0800 Test[43425:193320] Class is NSError, super class is NSObject
2019-02-01 15:32:05.494686+0800 Test[43425:193320] Following the isa pointer 0 times gives 0x7fff9b551b28
2019-02-01 15:32:05.494710+0800 Test[43425:193320] Following the isa pointer 1 times gives 0x0
2019-02-01 15:32:05.494727+0800 Test[43425:193320] Following the isa pointer 2 times gives 0x0
2019-02-01 15:32:05.494742+0800 Test[43425:193320] Following the isa pointer 3 times gives 0x0
2019-02-01 15:32:05.494760+0800 Test[43425:193320] NSObject's class is 0x7fffa215a140
2019-02-01 15:32:05.494778+0800 Test[43425:193320] NSObject's meta class is 0x0
typedef的用法: https://www.jianshu.com/p/38f08c4dc678
typedef enum Padding_type_e {
PAD_NO = 0,
PAD_ALL,
PAD_ADJUST,
PAD_MAX_INDICATOR /* Don't use this! It's used for sanity checks. */
} Padding_type;
typedef NS_ENUM(NSInteger, XRKPosterType) {
XRKPosterTypePoster = 2, // 海报
XRKPosterTypeLogion = 3 // 金句
};
typedef void(^responseBlock)(KWResponseObject *responseObject, NSError *error);
struct lame_global_struct;
typedef struct lame_global_struct lame_global_flags;
typedef lame_global_flags *lame_t;
typedef struct {
int header_parsed; /* 1 if header was parsed and following data was
computed */
int stereo; /* number of channels */
int samplerate; /* sample rate */
} mp3data_struct;
typedef struct Netscape_certificate_sequence {
ASN1_OBJECT *type;
STACK_OF(X509) *certs;
} NETSCAPE_CERT_SEQUENCE;
struct tagPOINT1
{
int x;
int y;
};
struct tagPOINT1 p1;
typedef struct tagPOINT
{
int x;
int y;
}POINT;
POINT p1;
objc_object与id
objc_object
是表示一个类的实例的结构体,它的定义如下(objc/objc.h
):
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
typedef struct objc_object *id;
所以当这样用id deledate = [NSArray new]
, 相当于是Any类型
objc_cache
struct objc_cache {
unsigned int mask /* total = mask + 1 */ OBJC2_UNAVAILABLE;
unsigned int occupied OBJC2_UNAVAILABLE;
Method buckets[1] OBJC2_UNAVAILABLE;
};
元类(Meta Class)
NSArray *array = [NSArray array];
这个例子中,+array消息发送给了NSArray类,而这个NSArray也是一个对象。既然是对象,那么它也是一个objc_object指针,它包含一个指向其类的一个isa指针。那么这些就有一个问题了,这个isa指针指向什么呢?为了调用+array方法,这个类的isa指针必须指向一个包含这些类方法的一个objc_class结构体。这就引出了meta-class的概念
meta-class是一个类对象的类。 当我们向一个对象发送消息时,runtime会在这个对象所属的这个类的方法列表中查找方法;而向一个类发送消息时,会在这个类的meta-class的方法列表中查找。
Objective-C的设计者让所有的meta-class的isa指向基类的meta-class,以此作为它们的所属类。即,任何NSObject继承体系下的meta-class都使用NSObject的meta-class作为自己的所属类,而基类的meta-class的isa指针是指向它自己。这样就形成了一个完美的闭环。
不知所云,看不去了。