用runtime创建类
下面的代码是创建了一个NSError的subClass和添加一个方法:
Class newClass = objc_allocateClassPair([NSError class], "RuntimeErrorSubClass", 0);
/*
* Class cls: 将要给添加方法的类,传的类型 [类名 class]
* SEL name: 将要添加的方法名,传的类型 @selector(方法名)
* IMP imp:实现这个方法的函数
* const char *types:表示我们要添加的方法的返回值和参数
”v@:”意思就是这已是一个void类型的方法,没有参数传入
*/
class_addMethod(newClass, @selector(report), (IMP)ReportFunction, "v@:");
objc_registerClassPair(newClass);
这个方法添加了ReportFunction方法,实现如下:
void ReportFunction(id self, SEL _cmd) {
NSlog(@"This object is %p.",self);
NSLog(@"Class is %@, and super is %@.", [self class], [self superclass]);
Class currentClass = [self class];
for (int i=1; i < 5; i++) {
NSlog(@"Following the isa pointer %d times gives %p", i, currentClass);
currentClass = object_getClass(currentClass);
}
NSLog(@"NSObject's class is %p", [NSObject class]);
NSLog(@"NSObject' meta class is %p", object_getClass([NSObject class]))
}
从这里看起来,从runtime创建类只有简单的三步:
1. 给“class pair”分配内存(使用objc_allocateClassPair).
2. 给类增加方法和成员变量.
3. 注册类(使用objc_registerClassPair).
那么这个class pair是指什么呢?应该就是指类和元类。
怎样把数据结构转变成对象呢?
每个对象都是由类具体化的,这是面向对象编程的基本原理,在object-C中,数据也具有这样的属性。任何具有一个指向类的指针的数据结构都可以被看作是一个对象。
在OC中,一个对象的类是由它的isa指针决定的,isa指向对象的类。
实际上,对象的基本定义是这样的:
typedef struct objc_objec {
Class isa;
} *id
从定义可以看出,任何一个具有指向一个类的指针的结构体都可以被看作是一个对象。
OC的一个非常重要的特性是,消息机制,如下例子:
[@"stringValue" writeToFile:@"/file.txt" atomically:YES encaoding:NSUTF8StringEncoding error:NULL];
这个工作的原理是,当你发送一个消息给一个对象(如这里的NSCFString),runtime根据isa指向对象的类(在这个例子中指的是NSCFString)。类中有所有对象的方法列表以及父类的方法列表(继承)。runtime就会遍历类和父类中的方法列表,匹配出消息中的方法(如writeToFile:atomically:encoding:error on NSString)并调用函数。
那么什么是元类(meta-class)呢?
在OC中,类同样是一个对象,这就意味着,可以直接发送消息给类,如:
NSStringEncoding defaultStringEncoding = [NSString defaultStringEncoding];
这个方法中,defaultStringEncoding就是直接调用的类方法。
类方法工作的原因是因为在OC中,每个类自身都是一个对象,也就是说每个类的结构体必须有isa指针,这样就能和对象的结构相兼容。
为了让我们能够唤起类中的方法,类的isa指针必须指向一个包含改方法的方法列表的类的结构体。这就是元类(meta-class)的定义了:元类就是类对象的类。如图表示:

简单描述这个过程就是:
* 当你发送一个消息给对象的时候,这个消息会在类的方法列表中寻找对应的响应。
* 当你发送一个消息给类的时候,消息会在元类的方法列表中寻找对应的响应。
因此,换句话说,元类保存了类的类方法。
总结
- 元类也是一个对象,元类存在一个基元类,基元类的isa指向自身。
- 每个类都有唯一的元类
- 元类保证了类对象的实例方法和类方法的继承
PS:
现在ObjC对象的结构已经更新了,代替isa指针的是结构体isa_t,这个结构体包含了但前对象指向的类的信息
struct objc_object {
isa_t isa;
};
union isa_t {
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls;
uintptr_t bits;
struct {
uintptr_t indexed : 1;
uintptr_t has_assoc : 1;
uintptr_t has_cxx_dtor : 1;
uintptr_t shiftcls : 44;
uintptr_t magic : 6;
uintptr_t weakly_referenced : 1;
uintptr_t deallocating : 1;
uintptr_t has_sidetable_rc : 1;
uintptr_t extra_rc : 8;
};
};