比较简单的一篇英文,重点是讲解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给出了一份精彩的图谱来展示这些关系:

http://www.sealiesoftware.com/blog/class%20diagram.pdf

实验证明:



为了证实以上的论述,让我们查看下开篇代码中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 分类: ios相关 ios技术 2015-03-07 15:41 51人阅读 评论(0) 收藏的更多相关文章

  1. 周赛-Toy Cars 分类: 比赛 2015-08-08 15:41 5人阅读 评论(0) 收藏

    Toy Cars time limit per test 1 second memory limit per test 256 megabytes input standard input outpu ...

  2. SQL 分组 加列 加自编号 自编号限定 分类: SQL Server 2014-11-25 15:41 283人阅读 评论(0) 收藏

    说明: (1)日期以年月形式显示:convert(varchar(7),字段名,120) , (2)加一列 (3)自编号: row_number() over(order by 字段名 desc) a ...

  3. Winfrom传值 分类: C# 2015-07-22 15:41 1人阅读 评论(0) 收藏

    以前对WinForm窗体显示和窗体间传值了解不是很清楚  最近做了一些WinForm项目,把用到的相关知识整理如下  A.WinForm中窗体显示  显示窗体可以有以下2种方法:  Form.Show ...

  4. 相对路径 分类: C# 2015-06-11 15:41 8人阅读 评论(0) 收藏

    .绝对路径     绝对路径是指文件在硬盘上真正存在的路径.例如"bg.jpg"这个图片是存放在硬盘的"E:\book\网页布局代码\第2章"目录下,那么 &q ...

  5. ubuntu中安装eclipse 分类: android ubuntu linux 学习笔记 2015-07-07 10:19 75人阅读 评论(0) 收藏

    上一篇说了安装jdk的事,于是趁热打铁,决定把eclipse也安装了. 下载这一系列就不用说了. 下载完成之后: 然后解压,解压之后文件剪切到/usr/software文件夹中,同时重命名为eclip ...

  6. ubuntu中安装jdk 分类: java 学习笔记 linux ubuntu 2015-07-06 17:49 74人阅读 评论(0) 收藏

    参考文献:ubuntu 13.04 安装 JDK 先去oracle官网下载jdk,这一段我就不赘述了. 下载好之后先解压,解压方式参见 linux常用的压缩与解压缩命令 ,解压之后,将文件剪贴至/us ...

  7. PC机安装Qt以及QT交叉编译环境 分类: OpenCV ZedBoard shell ubuntu Eye_Detection 2014-11-08 18:57 246人阅读 评论(0) 收藏

    PC: apt-get install qtcreator Qt Embedded for ZedBoard: 下载qt-everywhere-opensource-src-4.7.3.tar.gz, ...

  8. javascript闭包获取table中tr的索引 分类: JavaScript 2015-05-04 15:10 793人阅读 评论(0) 收藏

    使用javascript闭包获取table标签中tr的索引 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN& ...

  9. 安装hadoop1.2.1集群环境 分类: A1_HADOOP 2014-08-29 15:49 1444人阅读 评论(0) 收藏

    一.规划 (一)硬件资源 10.171.29.191 master 10.173.54.84  slave1 10.171.114.223 slave2 (二)基本资料 用户:  jediael 目录 ...

随机推荐

  1. JS 新浪API获取IP归属地

    http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js 返回值数据格式:var remote_ip_info = {“ret”:1,” ...

  2. jquery_api(事件一)

    一 .unload在火狐,谷歌无法弹出alerta是因为这两个浏览器默认组织alert弹出,unload事件可以进行一些对象销毁,事件解除绑定等清理工作. 如果你想在用户离开页面之前确认是否离开,最好 ...

  3. android 市场发布应用小结

    1:360平台发布应用 网址:http://dev.app.360.cn/ 2:腾讯应用宝 平台发布应用: 地址:http://op.open.qq.com/  (未审核通过的不能更新版本) 3:发布 ...

  4. SORT函数的使用方法(转载)

    sort函数的用法(转载出处:http://blog.sina.com.cn/s/blog_6439f26f01012xw3.html) 做ACM题的时候,排序是一种经常要用到的操作.如果每次都自己写 ...

  5. Bcdedit命令使用详解使用方法

    XP,WIN2003,VISTA,万indows,WIN2008多盘多系统多引导bcdedit的使用windows出了新系统vista,2008想赏赏鲜学习学习~~但又习惯于用旧的XP,2003,然而 ...

  6. mysql导出表结构

    在命令行下mysql的数据导出有个很好用命令mysqldump,它的参数有一大把,可以这样查看: mysqldump 最常用的: mysqldump -uroot -pmysql databasefo ...

  7. base64编码的图片字节流存入html页面中的显示

    在图片数据中加载到一个img标签,并如下处理 <img src="data:image/png;base64,...

  8. 有向图强连通分支的Tarjan算法讲解 + HDU 1269 连通图 Tarjan 结题报告

    题目很简单就拿着这道题简单说说 有向图强连通分支的Tarjan算法 有向图强连通分支的Tarjan算法伪代码如下:void Tarjan(u) {dfn[u]=low[u]=++index//进行DF ...

  9. iptables-过滤61开头的ip数据包

    iptables -F root@android:/system/bin # iptables -L -n iptables -L -n Chain INPUT (policy ACCEPT) tar ...

  10. FZU Problem 2029 买票问题(树状数组)

    当我看到题目是5秒的时候,压根没有想树状数组,一直奔着模拟队列去想了,最后也没搞定,赛后看到大神的题解才恍然大悟,原来如此,题目中有明显的暗示,求前n项和,骤然感叹,自己太low... 果然还是要多做 ...