objc_object 、objc_class、metaclass
2015-01-29 11:32
337 查看
[0] Outline
-- [1] id和Class
-- [2] 动态地操作类
-- [3] 实例化
[1] id和Class
在Objective-C中有一个特别的数据类型作为对象标识符:id,可以指向任何类型的对象。
通过 “可以指向任何类型的对象” 这一描述,猜想id实际上是指向Objective-C对象系统中的基类(继承体系中的祖先结构)的指针,在运行时是指向对象内存布局的基类部分。
第一眼看到id数据类型,我联想到了Python中的PyObject结构:
[cpp] view
plaincopy
typedef struct _object {
int ob_refcnt;
struct _typeobject *ob_type;
} PyObject;
该数据类型也是Python对象系统中的祖先类型,不过与id相对应的应该是PyObject *类型。
id数据类型是一个指向struct objc_object结构的指针:
[cpp] view
plaincopy
typedef struct objc_class *Class;
typedef struct objc_object {
Class isa;
} *id;
更确切地说,id是指向Class类型的指针,而Class又是指向struct objc_class结构的指针:
[cpp] view
plaincopy
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结构:
[cpp] view
plaincopy
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的存在。
知道了类的表示结构,我们可以动态地对类进行操作,加深理解。
[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是由类名来表示,比如下述代码中:
[cpp] view
plaincopy
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上的问题的解答:/article/1358540.html]
-- [1] id和Class
-- [2] 动态地操作类
-- [3] 实例化
[1] id和Class
在Objective-C中有一个特别的数据类型作为对象标识符:id,可以指向任何类型的对象。
通过 “可以指向任何类型的对象” 这一描述,猜想id实际上是指向Objective-C对象系统中的基类(继承体系中的祖先结构)的指针,在运行时是指向对象内存布局的基类部分。
第一眼看到id数据类型,我联想到了Python中的PyObject结构:
[cpp] view
plaincopy
typedef struct _object {
int ob_refcnt;
struct _typeobject *ob_type;
} PyObject;
该数据类型也是Python对象系统中的祖先类型,不过与id相对应的应该是PyObject *类型。
id数据类型是一个指向struct objc_object结构的指针:
[cpp] view
plaincopy
typedef struct objc_class *Class;
typedef struct objc_object {
Class isa;
} *id;
更确切地说,id是指向Class类型的指针,而Class又是指向struct objc_class结构的指针:
[cpp] view
plaincopy
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结构:
[cpp] view
plaincopy
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的存在。
知道了类的表示结构,我们可以动态地对类进行操作,加深理解。
#import <UIKit/UIKit.h> #import <objc/objc.h> #import <objc/runtime.h> #import "AppDelegate.h" void selfIntro(id self, SEL _cmd); int main(int argc, char *argv[]) { @autoreleasepool { /* 创建一个新的类,通过调用objc_allocateClassPair开始。 然后设置类的属性与功能,通过函数 class_addMethod和 class_addIvar。 当你完成建筑类,调用objc_registerClassPair。这个新类现在可以使用了。 */ /* 第一个参数:作为新类的超类,或用Nil来创建一个新的根类。 第二个参数:新类的名称 第三个参数:一般传0 */ // 类NSDemo的父类是NSObject Class demoClass = objc_allocateClassPair([NSObject class], "NSDemo", 0); BOOL isOk = NO; /* 向类添加方法 第一个参数:类 第二个参数:添加的SEL 第三个参数:SEL的实现函数 会覆盖父类的方法,但不会覆盖本类已存在的方法,如果本类已有这个方法存在,添加不会成功,要重写本类的方法实现 须用函数method_setImplementation */ //向methodLists指向添加数据 //"v@:" indicates the function type : v - void, @ - object, : - SEL isOk = class_addMethod(demoClass, @selector(intro), (IMP)&selfIntro, "v@:"); isOk == YES ? nil : NSLog(@"failed on class_addMethod\n"); /* 第一个参数:类名 不能是metaclass 第二个参数:实例变量名 不能已存在 第三个参数:sizeof(id) 第四个参数:log2(sizeof(id)) */ //向ivars指向添加数据 isOk = class_addIvar(demoClass,"myVar", sizeof(id), log2(sizeof(id)), "@"); isOk == YES ? nil : NSLog(@"failed on class_addIvar\n"); // 注册 objc_allocateClassPair 创建的类 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); return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } void selfIntro(id self, SEL _cmd) { NSLog(@"self: %@ -- _cmd: %s",self,_cmd); Class isa = object_getClass(self); 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 } }
2014-01-29 11:21:08.912 Caipiao[4593:610132] self: <NSDemo: 0x7fb44bc0a7d0> -- _cmd: intro 2014-01-29 11:21:08.923 Caipiao[4593:610132] != : 0x7fb44bc0a5b0, NSDemo 2014-01-29 11:21:08.927 Caipiao[4593:610132] != : 0x7fb44bc0a5e0, NSDemo 2014-01-29 11:21:08.933 Caipiao[4593:610132] == : 0x10b725d50, NSObject 2014-01-29 11:21:08.934 Caipiao[4593:610132] Hello,nil
[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是由类名来表示,比如下述代码中:
[cpp] view
plaincopy
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上的问题的解答:/article/1358540.html]
相关文章推荐
- 关于runtime的objc_getClass和object_getclass
- Xcode 【错误:duplicate symbol _OBJC_METACLASS_$_类名 in:】
- yate学习--yateclass.h--class YATE_API ObjList : public GenObject
- 刨根问底Objective-C Runtime(2)- Object & Class & Meta Class
- IOS——duplicate symbol _OBJC_METACLASS_$_ClassName错误(stackoverflow)
- 对象&类&元类(Object & Class & Meta Class)
- 刨根问底Objective-C Runtime(2)- Object & Class & Meta Class
- public static T CloneObject<T>(this T obj) where T:class{}
- Inside QT Series (九):QMetaObject class data members
- Inside Qt Series (八):Meta Object Class overview
- duplicate symbol _OBJC_METACLASS_$_ClassName
- duplicate symbol _OBJC_METACLASS_$_ClassName
- 'classobj' object is not iterable ?
- 对象&类&元类(Object & Class & Meta Class)
- Inside Qt Series (九):QMetaObject class data members
- 刨根问底Objective-C Runtime(2)- Object & Class & Meta Class
- duplicate symbol _OBJC_METACLASS_$_EMHostModel in:
- 友盟分享报错_OBJC_CLASS_$_QQApiImageArrayForQZoneObject
- QT中添加Q_OBJECT时编译提示obj : error LNK2001: 无法解析的外部符号 "public: virtual struct QMetaObject const错误解决方法
- Inside Qt Series (八):Meta Object Class overview