首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

详解Objective-C的meta-class(1)

详解Objective-C的meta-class(1)

在运行时创建类

以下代码演示运行时创建一个NSError的子类,同时添加一个实例方法给它:

    Class newClass =  
        objc_allocateClassPair([NSError class], "RuntimeErrorSubclass", 0);  
    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's meta class is %p",object_getClass([NSObject  class]));  
    }  

看起来一切都很简单,运行时创建类只需要三步:
1、为"class pair"分配空间(使用objc_allocateClassPair).
2、为创建的类添加方法和成员(上例使用class_addMethod添加了一个方法)。
3、注册你创建的这个类,使其可用(使用objc_registerClassPair)。

估计读者马上就要问:什么是“class pair"? objc_allocateClassPair只返回一个值:Class。那么pair的另一半在哪里呢?
是的,估计你已经猜到了这个另一半就是meta-class,也就是这篇短文的标题,但是要解释清楚它是什么,为什么需要它,还需要交代下OC的对象与类的相关背景。
一个数据结构何以成为一个对象?

每个对象都会有一个它所属的类。这是面向对象的基本概念,但是在OC中,这对所有数据结构有效。任何数据结构,只要在恰当的位置具有一个指针指向一个class,那么,它都可以被认为是一个对象。
在OC中,一个对象所属于哪个类,是由它的isa指针指向的。这个isa指针指向这个对象所属的class。
实际上,OC中对象的定义是如下的样子:

    typedef  struct  objc_object {  
          Class isa;  
    }*id;  

这个定义表明:任何以一个指向Class的指针作为首个成员的数据结构都可以被认为是一个objc_object.
最重要的特性就是,你可以向OC中的任何对象发送消息,如下这样:

【@”stringValue" writeToFile"/file.txt atomically:YES encoding: NSUTF8StringEncoding error:NULL];  

运行原理就是,当你向一个OC对象发送消息时(上文的@“stringValue”),运行时库会根据对象的isa指针找到这个对象所属的类(上文为例,会找到NSCFString类).这个类会包含一个所有实例方法的列表及一个指向superclass的指针以便可以找到父类的实例方法。运行时库会在类的方法列表以及父类(们)的方法列表中寻找符合这个selector(上文为例,这个selector是"writeToFile:atomically:encoding:error")的方法。找到后即运行这个方法。关键点就是类要定义这个你发送给对象的消息。
返回列表