iOS开发中的对象系统基础

来源:互联网 发布:无法无天吾知txt下载 编辑:程序博客网 时间:2024/05/17 00:15

[0] Outline

  -- [1] id和Class

  -- [2] 动态地操作类

  -- [3] 实例化


[1] id和Class

在Objective-C中有一个特别的数据类型作为对象标识符:id,可以指向任何类型的对象。

通过 “可以指向任何类型的对象” 这一描述,猜想id实际上是指向Objective-C对象系统中的基类(继承体系中的祖先结构)的指针,在运行时是指向对象内存布局的基类部分。


第一眼看到id数据类型,我联想到了Python中的PyObject结构:

typedef struct _object {    int ob_refcnt;    struct _typeobject *ob_type;} PyObject;

该数据类型也是Python对象系统中的祖先类型,不过与id相对应的应该是PyObject *类型。


id数据类型是一个指向struct objc_object结构的指针:

typedef struct objc_class *Class;typedef struct objc_object {    Class isa;} *id;

更确切地说,id是指向Class类型的指针,而Class又是指向struct objc_class结构的指针:

struct objc_class {     struct objc_class *isa;     struct objc_class *super_class;      const char *name;       long version;     long info;     long instance_size;     struct objc_ivar_list *ivars;     struct objc_method_list **methodLists;     struct objc_cache *cache;     struct objc_protocol_list *protocols;};

至此,可以看到Objective-C对象系统的基石:struct objc_class结构:

     isa指针:指向该对象所属类型的类型对象(Class Object)。在Objective-C中,类也是用对象来表示的,而类的isa指针指向它的metaclass(存储静态成员变量和类方法)。     super_class指针:指向父类。     name:类名称。     version:类的版本信息。     info:运行期使用的标志位,比如0x1(CLS_CLASS)表示该类为普通class,0x2(CLS_META)表示该类为     metaclass。     instance_size:实例大小,即内存所占空间。     ivars:指向成员变量列表的指针。     methodLists:根据标志位的不同可能指向不同,比如可能指向实例方法列表,或者指向类方法列表。     cache:因为Objective-C的消息转发需要查找dispatch table甚至可能需要遍历继承体系,所以缓存最近使用的方法。     protocols:类需要遵守的协议。

[2] 动态地操作类

由上知道了类也是一种对象,那么类对象也有一种类型,这种类型就是类的metaclass,因此类方法其实就是metaclass的成员方法,类和metaclass是配套出现的。

那么metaclass的isa指针和super_class指针怎么指向的呢?

如果metaclass对应基类,那么它的isa指向自身、super_class指针指向对应的类(基类);如果不是则isa指针指向基类的metaclass、super_class指针指向父类的metaclass。

基类的isa指针为nil。


这不禁让我又想起了Python中类似的设计思想,比如整型数字2的类型是PyIntObject,而PyIntObject类的类型是PyTypeObject,PyTypeObject的类型是PyTypeObject。最终止于此。

同样地,Python中也有metaclass的存在。


知道了类的表示结构,我们可以动态地对类进行操作,加深理解。

////  main.m//  HelloOC////  Created by Jason Lee on 12-2-17.//  Copyright (c) 2012年 XXX. All rights reserved.//#import <Foundation/Foundation.h>#import <objc/objc.h>#import <objc/runtime.h>void selfIntro(idself, SEL_cmd);int main (int argc, constchar * argv[]){        @autoreleasepool {        //Create class & metaclass as a pair        Class demoClass = objc_allocateClassPair([NSObjectclass], "NSDemo", 0);                BOOL isOk = NO;                //"v@:" indicates the function type : v - void, @ - object, : - SEL        //向methodLists指向添加数据        isOk = class_addMethod(demoClass, @selector(intro), (IMP)&selfIntro, "v@:");        isOk == YES ? nil : NSLog(@"failed on class_addMethod\n");                //向ivars指向添加数据        isOk = class_addIvar(demoClass,"myVar", sizeof(id), log2(sizeof(id)), "@");         isOk == YES ? nil : NSLog(@"failed on class_addIvar\n");                objc_registerClassPair(demoClass);                id demo = class_createInstance(demoClass, 0);                if ([demo respondsToSelector:@selector(intro)]) {            [demo performSelector:@selector(intro)];        }                object_setInstanceVariable(demo, "myVar", nil);        void *outValue = (void *)0x1;        object_getInstanceVariable(demo, "myVar", &outValue);        if (nil == outValue) {            NSLog(@"Hello,nil\n");  //printed        }                object_dispose(demo);    }        return0;}void selfIntro(idself, SEL_cmd) {    NSLog(@"selfIntro\n");        Class isa = self->isa;  //At first, isa is class NSDemo    while (1) {        if (isa == isa->isa) {  //Finally, NSObject's metaclass points to itself            NSLog(@"%p, %@", isa, objc_getMetaClass(class_getName([isa class])));            break;        }                NSLog(@"%p, %@", isa, objc_getMetaClass(class_getName([isa class])));        isa = isa->isa; //Then, isa is assigned to NSDemo's metaclass    }}


[3] 实例化

要实例化出一个对象,需要根据类的定义来进行。类的定义包括类名称、数据和操作数据的方法。

编译过程,类的信息会被记录下来,供runtime system使用,同时编译器会为每个类创建唯一的一个对象来表示它:class object。如果从功能上说,class object也是factory object,它能够执行类方法,负责创建实例。


从这个角度来看,我在思考class object是否就是metaclass,但是不能确认。

Apple官方文档TOCPL中Class Objects一章有这么一句,“a class object keeps the prototype of a class instance”,但metaclass并不能作为实例原型。

于是我认为class object是运行时class和metaclass结合起来的受限表现,能够访问编译器捕捉下来的类信息,没有成员变量,不能调用成员方法,但是可以执行类方法。

从源码层次来看,class object是由类名来表示,比如下述代码中:

int version = [NSString version];

NSString代表着class object。


首先,class object会被runtime system发送initialize消息进行初始化,让其做好运行时的准备,比如初始化静态变量。

之后,可以调用class object的方法(类方法)alloc来为新的实例对象分配内存空间,将其所有变量初始化为0,isa指针指向所属类。

最后再调用init函数进行必要的初始化。


写到这里的时候,突然要变更办公位置,思路被打断了,就先写到这里。

最后,留一个在SO上面看到的问题,我也疑惑,只能有几分猜测:http://stackoverflow.com/questions/8847146/whats-is-methodlists-attribute-of-the-structure-objc-class-for

[这篇文章是我对SO上的问题的解答:http://blog.csdn.net/jasonblog/article/details/7303618]


[Last Updated] 2012-03-17


Jason Lee @ 杭州

博客:http://blog.csdn.net/jasonblog

微博:http://weibo.com/jasonmblog

GitHub: https://github.com/siqin
原创粉丝点击