比较简单的一篇英文,重点是讲解meta-class。翻译下,加深理解。

原文标题:What is a meta-class in Objective-C?

原文地址:http://www.cocoawithlove.com/2010/01/what-is-meta-class-in-objective-c.html

本篇将会探讨一个在Objective-C中相对陌生的概念 -- meta-class。OC中的每一个类都会有一个与之相关联的meta class,但是你却几乎永远也不会直接使用到,它们始终笼罩着一层神秘的面纱。笔者将以运行时动态创建一个class为引,通过剖析创建的class pair来弄明白到底meta-class是什么以及更深入的了解它对于OC中对象、类的意义。

 

在运行时创建类

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

  1. Class newClass =
  2. objc_allocateClassPair([NSError class], "RuntimeErrorSubclass", 0);
  3. class_addMethod(newClass, @selector(report), (IMP)ReportFunction, "v@:");
  4. objc_registerClassPair(newClass);

函数ReportFunction就是添加的实例方法的具体实现,如下:

  1. void ReportFunction(id self, SEL _cmd)
  2. {
  3. NSLog(@"This object is %p.",self);
  4. NSLog(@"Class is %@, and super is %@.",[self class],[self superclass]);
  5. Class currentClass = [self class];
  6. for( int i = 1; i < 5; ++i )
  7. {
  8. NSLog(@"Following the isa pointer %d times gives %p",i,currentClass);
  9. currentClass = object_getClass(currentClass);
  10. }
  11. NSLog(@"NSObject's class is %p", [NSObject class]);
  12. NSLog(@"NSObject's meta class is %p",object_getClass([NSObject class]));
  13. }

看起来一切都很简单,运行时创建类只需要三步:
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中对象的定义是如下的样子:

  1. typedef struct objc_object {
  2. Class isa;
  3. }*id;

这个定义表明:任何以一个指向Class的指针作为首个成员的数据结构都可以被认为是一个objc_object.

最重要的特性就是,你可以向OC中的任何对象发送消息,如下这样:

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

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

什么是meta-class?


至此,你可能已经知道,一个OC的类其实也是一个对象,意思就是你可以向一个类发送消息。
NSStringEncoding defaultStringEncoding = [NSString defaultStringEncoding];
在这个例子中,defaultStringEncoding 被发送给了NSString类。因为每一个OC的类本身也是一个对象。也就是说Class的数据结构必然也是以isa指针开始的在二进制级别上与objc_object是完全兼容的。然后一个类结构的下一个字段一定是一个指向super class的指针(或者指向nil,对于基类而言)。
一个类如何定义有很多方法,依赖于你的运行时库版本,但是不管哪种方法,他们都是以一个isa作为第一个字段,接着是superclass字段。

  1. typedef struct objc_class *Class;
  2. struct objc_class{
  3. Class isa;
  4. Class super_class;
  5. /*followed by runtime specific details...*/
  6. };

为了可以调用类方法,这个类的isa指针必须指向一个包含这些类方法的类结构体。
这样就引出了meta-class的概念:meta-class是一个类对象的类。
简单解释下:
       当你向一个对象发送消息时,runtime会在这个对象所属的那个类的方法列表中查找。
       当你向一个类发送消息时,runtime会在这个类的meta-class的方法列表中查找。
meta-class之所以重要,是因为它存储着一个类的所有类方法。每个类都会有一个单独的meta-class,因为每个类的类方法基本不可能完全相同。

meta-class的类又是什么呢?


meta-class,就像Class一样,也是一个对象。你依旧可以向它发送消息调用函数,自然的,meta-class也会有一个isa指针指向其所属类。所有的meta-class使用基类的meta-class作为他们的所属类。具体而言,任何NSObject继承体系下的meta-class都使用NSObject的meta-class作为自己所属的类。
根据这个规则,所有的meta-class使用基类的meta-class作为它们的类,而基类的meta-class也是属于它自己,也就是说基类的meta-class的isa指针指向它自己。(译:完美的闭环)

类和meta-class的继承


就像一个类使用super_class指针指向自己的父类一样,meta-class的super_class会指向类的super_class的meta-class。一直追溯到基类的meta-class,它的super_class会指向基类自身。(译:万物归根)
这样一来,整个继承体系中的实例、类和meta-class都派生自继承体系中的基类。对于NSObject继承体系来说,NSObject的实例方法对体系中所有的实例、类和meta-class都是有效的;NSObject的类方法对于体系中所有的类和meta-class都是有效的。
用文字描述总会让人迷糊,Greg Parker给出了一份精彩的图谱来展示这些关系:
点击打开链接

实验证明:


为了证实以上的论述,让我们查看下开篇代码中ReportFunction的输出。这个函数的目的就是沿着isa指针进行打印。
为了运行ErportFunction,我们需要创建一个实例,并调用report方法。

  1. id instanceOfNewClass = [[newClass alloc]initWithDomain:@"some Domain" code:0 userInfo:nil];
  2. [instanceOfNewClass performSelector:@"report)];
  3. [instanceOfNewClass release];

因为我们并没有对report方法进行声明,所以我们使用performSelector进行调用,这样避免编译器警告。

然后ReportFunction函数会沿着isa进行检索,来告诉我们class,meta-class以及meta-class的class是什么样的情况:

【注:ReportFunction使用object_getClass来获取isa指针指向的类,因为isa指针是一个受保护成员,你不能直接访问其他对象的isa指针。ReportFunction没有使用class方法是因为在一个类对象上调用这个方法是无法获得meta-class的,它只是返回这个类而已。(所以[NSString class]只是返回NSString类,而不是NSString的meta-class]
以下是程序的输出:

  1. This object is 0x10010c810.
  2. Class is RuntimeErrorSubclass, and super is NSError.
  3. Followingthe isa pointer 1times gives 0x10010c600
  4. Followingthe isa pointer 2times gives 0x10010c630
  5. Followingthe isa pointer 3times gives 0x7fff71038480
  6. Followingthe isa pointer 4times gives 0x7fff71038480
  7. NSObject's class is 0x7fff710384a8
  8. NSObject's meta class is 0x7fff71038480

观察通过isa获得的地址:
对象的地址是      0x10010c810.
类的地址是         0x10010c600.
类的meta-class地址是  0x10010c630.
类的meta-class的类地址是                 0x7fff71038480.(即NSOjbect的meta-class)
NSObject的meta-class的类地址是它自身。
这些地址的值并不重要,重要的是它们说明了文中讨论的从类到meta-class到NSObject的meta-class的整个流程。

结论:


meta-class是类对象的类,每个类都有自己单独的meta-class。所有的类对象并不会属于同一个meta-class。
meta-class要保证类对象具有继承体系中基类的所有实例和类方法,以及继承体系中的所有中间类方法。对于所有NSObject继承体系下的类,NSObject的实例方法和协议方法对他们和他们meta-class的对象都要有效。
所有的meta-class使用基类的meta-class作为自己的基类,对于顶层基类的meta-class也是一样,只是它指向自己而已。

详解Objective-C的meta-class的更多相关文章

  1. jQuery Validate验证框架详解

    转自:http://www.cnblogs.com/linjiqin/p/3431835.html jQuery校验官网地址:http://bassistance.de/jquery-plugins/ ...

  2. 【转】jQuery Validate验证框架详解

    jQuery校验官网地址:http://bassistance.de/jquery-plugins/jquery-plugin-validation 一.导入js库 <script type=& ...

  3. jQuery Validate验证框架详解(jquery.validate.min.js)

    原博客 jQuery Validate验证框架详解 jQuery校验官网地址:https://jqueryvalidation.org/ 一.导入js库 <script type="t ...

  4. jQuery Validate验证框架详解(转)

    jQuery校验官网地址:http://bassistance.de/jquery-plugins/jquery-plugin-validation 一.导入js库 <script type=& ...

  5. 浏览器 HTTP 协议缓存机制详解--网络缓存决策机制流程图

    1.缓存的分类 2.浏览器缓存机制详解 2.1 HTML Meta标签控制缓存 2.2 HTTP头信息控制缓存 2.2.1 浏览器请求流程 2.2.2 几个重要概念解释 3.用户行为与缓存 4.Ref ...

  6. Meta标签详解(HTML JAVASCRIPT)

    Meta标签详解,在网上转的,希望对大家有用 您的个人网站即使做得再精彩,在“浩瀚如海”的网络空间中,也如一叶扁舟不易为人发现,如何推广 个人网站,人们首先想到的方法无外乎以下几种: ● 在搜索引擎中 ...

  7. 最全html5 meta设置详解 (转)

    meta 详解,html5 meta 标签日常设置   <!DOCTYPE html> <!-- 使用 HTML5 doctype,不区分大小写 --> <html la ...

  8. 网页设计:Meta标签详解

    很多人忽视了HTML标签META的强大功效,一个好的META标签设计可以大大提高你的个人网站被搜索到的可能性,有兴趣吗,谁我来重新认识一下META标签吧! META标签是HTML语言HEAD区的一个辅 ...

  9. meta标签详解(meta标签的作用)///////////////////////////转

    meta标签详解(meta标签的作用) 很多人却忽视了HTML标签META的强大功效,一个好的META标签设计可以大大提高你的个人网站被搜索到的可能性,有兴趣吗,谁我来重新认识一下META标签吧   ...

  10. HTML中Meta属性http-equiv="X-UA-Compatible"详解

    HTML下head中的http-equiv="X-UA-Compatible"详解: X-UA-Compatible是针对IE8新加的一个设置,对于IE8之外的浏览器是不识别的,这 ...

随机推荐

  1. C语言itoa()函数和atoi()函数详解(整数转字符)

    http://c.biancheng.net/cpp/html/792.html C语言提供了几个标准库函数,可以将任意类型(整型.长整型.浮点型等)的数字转换为字符串. 以下是用itoa()函数将整 ...

  2. nginx几个知识点汇总

    WHY? 为什么用Nginx而不用LVS? 7点理由足以说明一切:1 .高并发连接: 官方测试能够支撑 5 万并发连接,在实际生产环境中跑到 2 - 3 万并发连接数.?2 .内存消耗少: 在 3 万 ...

  3. 组策略限制添加用户作为服务登录导致ITAtomcat服务无法启动(log on as a service)

    [故障类型]:ITA tomcat服务器无法启动. [关 键 词]:Logon as a service  作为服务登录  tomcat  loggeter [适用版本]:FusionCloud So ...

  4. MAC下编译FFMPEG

    1.下载ffmpeg,我使用xcode自带的git下载. 或者直接下载压缩包: 2.下载gas-preprocessor脚本 https://raw.github.com/mansr/gas-prep ...

  5. win7打开或关闭windows功能 提示“出现错误,并非所有的功能被更改”,管理员权限惹的祸

    2013-07-25 18:12:06 最近要用到windows的telnet功能,本来是很简单的事情,因为管理员权限的问题,花了不少时间,才发现是管理员权限惹的祸,更滑稽的是,自己一直以来都不是管理 ...

  6. JavaScript DOM高级程序设计2.3 this--我要坚持到底!

    先从一个例子说起 var sound = 'Roar'; function myOrneryBeast() { this.style.color='green';//window 方法被调用时所属的对 ...

  7. 取出block所对应的hash值

    /**********************************************************************//** Gets the hash value of t ...

  8. 一致性hash算法 - consistent hashing

    consistent hashing 算法早在 1997 年就在论文 Consistent hashing and random trees 中被提出,目前在 cache 系统中应用越来越广泛: 1 ...

  9. 【转】Git详解之一:Git起步

    原文网址:http://blog.jobbole.com/25775/ 原文:<Pro Git> 起步 本章介绍开始使用 Git 前的相关知识.我们会先了解一些版本控制工具的历史背景,然后 ...

  10. (转)MySQL数据库引擎ISAM MyISAM HEAP InnoDB的区别

    转自:http://blog.csdn.net/nightelve/article/details/16895917 MySQL数据库引擎取决于MySQL在安装的时候是如何被编译的.要添加一个新的引擎 ...