【IT168技术】最近打算写一些ObjC中比较底层的东西,尤其是 runtime 相关的。苹果已经将 ObjC runtime 代码开源了,我们可以从:http://opensource.apple.com/source/objc4/objc4-493.9/runtime/ 浏览源代码,或点此下载源代码。

  从哪里入手呢?那当然是最基本的类与对象。与C++相比,ObjC中的类与对象结构要简洁与一致得多(参考《深度探索C++对象模型》,你就知道C++中类与对象结构的复杂)。本文将详细讲解ObjC中类与对象的结构,下回将讲如何在 runtime 时操作类。

  我们可以在/usr/include/objc/objc.h 和 runtime.h 中找到对 class 与 object 的定义:

typedef struct objc_class *Class;
typedef struct objc_object {
    Class isa;
} *id;

  Class 是一个 objc_class 结构类型的指针;而 id(任意对象) 是一个 objc_object 结构类型的指针,其第一个成员是一个 objc_class 结构类型的指针。注意这里有一关键的引申解读:内存布局以一个 objc_class 指针为开始的所有东东都可以当做一个 object 来对待! 那 objc_class 又是怎样一个结构体呢?且看:

struct objc_class
{
    struct objc_class*isa; //指针指向metaClass,存储类方法列表(带加号的),和成员变量
    struct objc_class*super_class;
    constchar*name;
    longversion;
    longinfo;
    longinstance_size;
    struct objc_ivar_list*ivars;
    struct objc_method_list**methodLists; //存储实例方法(带减号的),和成员变量
    struct objc_cache*cache;
    struct objc_protocol_list*protocols;
}

  objc_class 结构体的各成员介绍如下:

  isa:是一个 objc_class 类型的指针,看到这里,想起我前面的引申解读了没?内存布局以一个 objc_class 指针为开始的所有东东都可以当做一个 object 来对待! 这就是说 objc_class 或者说类其实也可以当做一个 objc_object 对象来对待!对象是对象,类也是对象,是不是有点混淆?别急,ObjC发明(or 重用)了一个术语来区分这两种不同的对象:类对象(class object)与实例对象(instance object)。OK,名称混淆的问题解决,下面我将使用这两个术语来区分不同的对象,而使用“对象”这一术语来泛指所有的对象。ObjC还对类对象与实例对象中的 isa 所指向的类结构作了不同的命名:类对象中的 isa 指向类结构被称作 metaclass,metaclass 存储类的static类成员变量与static类成员方法(+开头的方法);实例对象中的 isa 指向类结构称作 class(普通的),class 结构存储类的普通成员变量与普通成员方法(-开头的方法)。

  super_class:一看就明白,指向该类的父类呗!如果该类已经是最顶层的根类(如 NSObject 或 NSProxy),那么 super_class 就为 NULL。

  好,先中断一下其他类结构成员的介绍,让我们厘清一下在继承层次中,子类,父类,根类(这些都是普通 class)以及其对应的 metaclass 的 isa 与 super_class 之间关系:

  规则一:类的实例对象的 isa 指向该类;该类的 isa 指向该类的 metaclass;

  规则二:类的 super_class 指向其父类,如果该类为根类则值为 NULL;

  规则三:metaclass 的 isa 指向根 metaclass,如果该 metaclass 是根 metaclass 则指向自身;

  规则四:metaclass 的 super_class 指向父 metaclass,如果该 metaclass 是根 metaclass 则指向该 metaclass 对应的类;

  好吧,文字总是那么乏力,有图有真相!

  

  那么 class 与 metaclass 有什么区别呢?

  class 是 instance object 的类类型。当我们向实例对象发送消息(实例方法)时,我们在该实例对象的 class 结构的 methodlists 中去查找响应的函数,如果没找到匹配的响应函数则在该 class 的父类中的 methodlists 去查找(查找链为上图的中间那一排)。如下面的代码中,向str 实例对象发送 lowercaseString 消息,会在 NSString 类结构的 methodlists 中去查找 lowercaseString 的响应函数。

  NSString * str;[str lowercaseString];

  metaclass 是 class object 的类类型。当我们向类对象发送消息(类方法)时,我们在该类对象的 metaclass 结构的 methodlists 中去查找响应的函数,如果没有找到匹配的响应函数则在该 metaclass 的父类中的 methodlists 去查找(查找链为上图的最右边那一排)。如下面的代码中,向 NSString 类对象发送 stringWithString 消息,会在 NSString 的 metaclass 类结构的 methodlists 中去查找 stringWithString 的响应函数。

  [NSString stringWithString:@"str"];

  好,至此我们明白了类的结构层次,让我们接着看类结构中的其他成员。

  name:一个 C 字符串,指示类的名称。我们可以在运行期(runTime),通过这个名称查找到该类(通过:id objc_getClass(const char *aClassName))或该类的 metaclass(id objc_getMetaClass(const char *aClassName));

  version:类的版本信息,默认初始化为 0。我们可以在运行期对其进行修改(class_setVersion)或获取(class_getVersion)。

  info:供运行期使用的一些位标识。有如下一些位掩码:

  CLS_CLASS (0x1L) 表示该类为普通 class ,其中包含实例方法和变量;

  CLS_META (0x2L) 表示该类为 metaclass,其中包含类方法;

  CLS_INITIALIZED (0x4L) 表示该类已经被运行期初始化了,这个标识位只被 objc_addClass 所设置;

  CLS_POSING (0x8L) 表示该类被 pose 成其他的类;(poseclass 在ObjC 2.0中被废弃了);

  CLS_MAPPED (0x10L) 为ObjC运行期所使用

  CLS_FLUSH_CACHE (0x20L) 为ObjC运行期所使用

  CLS_GROW_CACHE (0x40L) 为ObjC运行期所使用

  CLS_NEED_BIND (0x80L) 为ObjC运行期所使用

  CLS_METHOD_ARRAY (0x100L) 该标志位指示 methodlists 是指向一个 objc_method_list 还是一个包含 objc_method_list 指针的数组;

  instance_size:该类的实例变量大小(包括从父类继承下来的实例变量);

  ivars:指向 objc_ivar_list 的指针,存储每个实例变量的内存地址,如果该类没有任何实例变量则为 NULL;

  methodLists:与 info 的一些标志位有关,CLS_METHOD_ARRAY 标识位决定其指向的东西(是指向单个 objc_method_list还是一个 objc_method_list 指针数组),如果 info 设置了 CLS_CLASS 则 objc_method_list 存储实例方法,如果设置的是 CLS_META 则存储类方法;

  cache:指向 objc_cache 的指针,用来缓存最近使用的方法,以提高效率;

  protocols:指向 objc_protocol_list 的指针,存储该类声明要遵守的正式协议。

  总结:

  ObjC 为每个类的定义生成两个 objc_class ,一个即普通的 class,另一个即 metaclass。我们可以在运行期创建这两个 objc_class 数据结构,然后使用 objc_addClass 动态地创建新的类定义。这个够动态够强大的吧?下回讲演示如何在运行期动态创建新类。

转载于:https://www.cnblogs.com/pengyingh/articles/2353519.html

苹果iOS开发深入浅出Cocoa之类与对象相关推荐

  1. 苹果ios开发一年的工作笔记

    苹果ios开发一年的工作笔记 退回输入键盘 - (BOOL) textFieldShouldReturn:(id)textField{ [textField resignFirstResponder] ...

  2. 苹果iOS开发系列--详解Swift 3.0语言的重大变化

    概述 从写第一篇Swift文章的时候到现在Swift已经从1.2发展到了今天的3.0,这期间由于Swift目前还在发展阶段并不能向下兼容,因此第一篇文章中的部分代码在当前的Xcode环境中已经无法运行 ...

  3. 苹果IOS开发常用的第三方库总结

    网络通信 1.ASIHTTPRequest 这是一个经典的老库,功能完全而强大,但已经停止更新很久了(iOS5.0停止更新,但是我最近看github上这个项目有新改动).在不同iOS版本上略微有一些小 ...

  4. iOS开发之谓词Predicate和对象数组的排序

    我们在开发中经常使用的Predicate谓词,主要是正则表达式的使用,今天给大家简单的讲讲怎样去使用谓词. 因为内容比较简单,所以直接上代码展示: NSMutableArray *people_arr ...

  5. iOS开发基础:OC数组对象NSArray的常用方法

    本文介绍了OC的数组对象的基本方法的使用: 因为OC的数组中存储的为对象类型,所以我们可以新建一个Person类,通过Person生成对象进行操作. 其中Person.h中的代码为: [objc] v ...

  6. 苹果iOS开发 解析描述文件 读取mobileprovisioning profile

    如果想使用命令行自动打包ios,就需要从描述文件中获取到相关信息,本文介绍如何解析描述文件. 工具使用Mac OS自带的命令: plistBuddy="/usr/libexec/PlistB ...

  7. [Cocoa]深入浅出Cocoa系列

    深入浅出Cocoa系列 罗朝辉 (http://www.cnblogs.com/kesalin/) 本文遵循"署名-非商业用途-保持一致"创作公用协议 这是本人在研究 Cocoa  ...

  8. [深入浅出Cocoa]详解键值观察(KVO)及其实现机理

    [深入浅出Cocoa]详解键值观察(KVO)及其实现机理 本文转载至    罗朝辉 (http://www.cppblog.com/kesalin/) 本文遵循"署名-非商业用途-保持一致& ...

  9. [深入浅出Cocoa]之消息(二)-详解动态方法决议(Dynamic Method Resolution)

    [深入浅出Cocoa]之消息(二)-详解动态方法决议(Dynamic Method Resolution) 罗朝辉 (http://www.cnblogs.com/kesalin/) 本文遵循&quo ...

最新文章

  1. javascript:子窗口和父窗口交互
  2. 首航节能:光热行业刚起步 子公司处于亏损状态
  3. linux操作系统学什么,Linux学习-第一天-什么是操作系统
  4. storm消息可靠机制(ack)的原理和使用
  5. 曾经一手好牌,但如今却被网友怼或已堕落
  6. 配置sharepoint的在多个域环境中的kerberos认证
  7. html如何整齐排列选择框,html – 如何均匀地排列多个内嵌块元素?
  8. C#中类的默认访问是私有的
  9. android 怎么反编译,Android反编译工具的用法
  10. 【深度学习|数据集】Python 划分训练集和验证集
  11. Current_Path 获取脚本所在路径(当前路径),取当前时间做文件名(uformat)
  12. python求解立方根_求解立方根
  13. 计算机专业Java毕设怎么做
  14. mysql1310错误_救命啊,MySQL崩溃啦...
  15. 云服务器的“弹性”体现在哪?
  16. iverilog仿真问题
  17. 烧得七荤八素了,完了这下,本来现在应该在学校做网站的,然而半小时前还摊在床上哼哼唧唧。
  18. vue框架项目中使用阿里矢量图标库
  19. vs qt 无法打开包括文件: “QtCore/qconfig.h”
  20. 教学、会议、信息发布同屏直播满足流媒体录播、直播软件之 libEasyScreenLive通过D3D方式实现屏幕采集

热门文章

  1. android gradle NDK简介
  2. lambda,reserve list, list comprehension, string of slice
  3. Android Studio稍微较新的版本下载
  4. python之模块的导入和用户的交互格式化输出
  5. Python BeautifuSoup4 爬表格
  6. 实时统计分析技术浅谈
  7. C++ 整型和字符串相互转换
  8. 在ubuntu16上新创建了一个用户,通过xrdp远程连接时出现灰屏,鼠标是“x”号
  9. ubuntu 中 notepad 安装
  10. crop和resize操作区别