魏名华

不要偷懒,做更好的自己

Nothing


No Welcome Message

Runtime

重识 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 Runtime 运行时

类与对象

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指针是指向它自己。这样就形成了一个完美的闭环。

不知所云,看不去了。