详解Objective-C的meta-class

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

比较简单的一篇英文,重点是讲解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的子类,同时添加一个实例方法给它:

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")的方法。找到后即运行这个方法。关键点就是类要定义这个你发送给对象的消息。


什么是meta-class?
至此,你可能已经知道,一个OC的类其实也是一个对象,意思就是你可以向一个类发送消息。

NSStringEncoding defaultStringEncoding = [NSString defaultStringEncoding];


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


typedef struct objc_class *Class;  
struct objc_class{  Class isa;  Class super_class;  /*followed by runtime specific details...*/  
};  

 

为了可以调用类方法,这个类的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方法。


id instanceOfNewClass = [[newClass alloc]initWithDomain:@"some Domain" code:0 userInfo:nil];  
[instanceOfNewClass performSelector:@"report)];  
[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]
以下是程序的输出:


This object is 0x10010c810.  
Class is RuntimeErrorSubclass, and super is NSError.  
Followingthe isa pointer 1times gives 0x10010c600  
Followingthe isa pointer 2times gives 0x10010c630  
Followingthe isa pointer 3times gives 0x7fff71038480  
Followingthe isa pointer 4times gives 0x7fff71038480  
NSObject's class is 0x7fff710384a8  
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也是一样,只是它指向自己而已

转载于:https://my.oschina.net/mexiaobai1315/blog/878712

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/282367.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Nginx 模块的使用

Nginx模块的使用,就是在Nginx配置文件中的http、server、location中添加参数&#xff0c;进行多一项或几项处理一、 实现响应内容替换 1、sub_module二、Nginx的请求限制 1、连接频率限制 limit_conn_module 2、请求频率限制 limit_req_module 注: HTTP请求建立在一次…

Question | 网站被黑客扫描撞库该怎么应对防范?

本文来自网易云社区在安全领域向来是先知道如何攻&#xff0c;其次才是防。针对题主的问题&#xff0c;在介绍如何防范网站被黑客扫描撞库之前&#xff0c;先简单介绍一下什么是撞库。撞库是黑客通过收集互联网已泄露的用户和密码信息&#xff0c;生成对于的字典表&#xff0c;…

十倍程序员 | 使用 Source Generator 将 JSON 转换成 C# 类

前言有时候&#xff0c;我们需要将通过 WebAPI 接收 JSON 字符串转换成 C# 代码。Visual Studio 提供了一个功能菜单可以轻松实现&#xff1a;执行完成后&#xff0c;它会将生成的代码放在打开的的代码窗口中。但是&#xff0c;如果有多个 JSON 字符串需要转换&#xff0c;这个…

Delphi对话框初始地址InitialDir

我的电脑&#xff1a;SaveDialog1.InitialDir : ::{20D04FE0-3AEA-1069-A2D8-08002B30309D};// My Computer {20D04FE0-3AEA-1069-A2D8-08002B30309D}// Network Neighborhood {208D2C60-3AEA-1069-A2D7-08002B30309D}// Recycled {645FF040-5081-101B-9F08-00AA002F954E} 另外…

[python] 解决pip install download速度过慢问题 更换豆瓣源

""" python建立pip.ini.py 2016年4月30日 03:35:11 codegay """import osini"""[global] index-url https://pypi.doubanio.com/simple/ [install] trusted-hostpypi.doubanio.com """ pippathos.environ["…

Maven组件通过命令上传本地和私有仓库

安装本地包到本地仓库&#xff1a;mvn install:install-file -DgroupIdcom.xxx -DartifactIdmqtt-server-client -Dversion1.0.1 -Dpackagingjar -DfileE:\__vdt\MVVP\mqtt-server-client-1.0.1.jar -DpomFileE:\__vdt\MVVP\pom.xml安装本地包到私有仓库&#xff1a;mvn deploy…

Nginx -静态资源Web服务

一、静态资源类型 注&#xff1a;非服务器动态生成的文件 1、浏览器端渲染 HTML、css、js 2、图片 jpeg、gif、png 3、视频 flv、MPEG 4、文件 TXT、等任意下载文件二、静态资源服务配置1、配置语法-文件读取 syntax&#xff1a;sendfile on|off default&#xff1a;sendfi…

微软Microsoft Azure 机器学习工作室的案例之Image Classification using DenseNet

点击上方蓝字关注我们&#xff08;本文阅读时间&#xff1a;10分钟)Microsoft Azure Machine Learning Studio是微软强大的机器学习平台&#xff0c;在设计器中&#xff0c;微软内置了15个场景案例&#xff0c;但网上似乎没有对这15个案例深度刨析的分析资料&#xff0c;所以我…

java小基础之instanceof运算符

instanceof主要用来判断一个类是否实现了某个接口&#xff0c;或者判断一个实例对象是否属于一个类。 1. 判断一个对象是否属于一个类 boolean result p instanceof Student; 2. 对象类型强制转换前的判断 Person p new Student(); //判断对象p是否为Student类的实例 if(p in…

音乐分类

代码&#xff1a; 1 import numpy as np2 from scipy import fft3 from scipy.io import wavfile4 from sklearn.linear_model import LogisticRegression5 import random6 """7 使用logistic regression处理音乐数据&#xff0c;音乐数据训练样本的获得是使…

Problem C: 类的初体验(III)

Description 定义一个类Data&#xff0c;只有一个double类型的属性和如下4个方法&#xff1a; 1. 缺省构造函数&#xff0c;将属性初始化为0&#xff0c;并输出“Initialize a data 0”。 2. 带参构造函数&#xff0c;将属性初始化为指定参数&#xff0c;并输出“Initialize…

Nginx- 实现跨域访问

一、什么是跨域 跨域&#xff1a;由于浏览器的同源策略&#xff0c;即属于不同域的页面之间不能相互访问各自的页面内容。详细见下表&#xff1a; 注&#xff1a;同源策略&#xff0c;单说来就是同协议&#xff0c;同域名&#xff0c;同端口 URL说明是否允许通信http://www.a…

不管对不对,先把闹钟关了再说

小榆提前关闭早上闹钟&#xff0c;几乎工作日的早晨都是被这魔怔的铃声给拉扯醒&#xff0c;无论有多么不愿还是痛苦&#xff0c;可对这闹钟也无可奈何&#xff0c;就算一时果断掐掉接下来是另一回麻烦事。最后一天&#xff0c;已经顾不得多少&#xff0c;没什么令人惧怕的人或…

pycharm(windows)安装及其设置中文菜单

pycharm&#xff08;windows&#xff09;安装及其设置中文菜单 1.下载 在官网&#xff08;http://www.jetbrains.com/pycharm/download/#sectionwindows&#xff09;进行下载 或者到百度云进行下载 专业版&#xff1a;链接&#xff1a;http://pan.baidu.com/s/1bSSRds 密码&…

Tomcat定义虚拟主机案例

Tomcat定义虚拟主机案例 作者&#xff1a;尹正杰 版权声明&#xff1a;原创作品&#xff0c;谢绝转载&#xff01;否则将追究法律责任。 一.准备环境 1>.创建web程序的根目录 [rootyinzhengjie ~]# mkdir -pv /home/yinzhengjie/data/www/webapps/ROOT mkdir: created direc…

node服务成长之路

我们的系统也从第一代平台开始到现在第四代平台更换中&#xff0c;对这四代平台做一个简单的介绍&#xff1a; 第一代平台&#xff0c;主要是集中式&#xff0c;以快速上线为目的&#xff1b;第二代平台主要是分布式改造&#xff0c;缓解各服务压力&#xff1b;第三代平台主要做…

将域名绑定到ip上,并实现访问不同二级子域名对应不同目录

一、将域名绑定到ip上1、环境介绍&#xff1a;阿里云服务器ESC&#xff08;美国硅谷&#xff09; 2、购买域名 3、备案 注&#xff1a;由于我买的是美国地区服务器&#xff0c;所以不用备案&#xff0c;如果买的国内服务器&#xff0c;这里需要添加一个备案操作。 4、域名实名认…

ABP vNext微服务架构详细教程(补充篇)——单层模板(中)

框架搭建2聚合服务这里我们将聚合服务命名为Domain.Core和基础服务层一致&#xff0c;我们先通过命令创建单层模板项目Domain.Core&#xff0c;这里我们删除wwwroot、Data、Entities、Localization、ObjectMapping文件夹及其所有子文件&#xff0c;并删除package.json文件和Ser…

谈一谈synchronized关键词

1.使用 java中的每一个对象都可以作为synchronized的锁进行代码同步&#xff0c;常见的形式 同步代码块锁是synchronized括号内的对象普通成员方法上&#xff0c;锁是当前的对象&#xff0c;synchronized(this)静态方法上&#xff0c;锁是当前类的Class对象2. 原理 synchronize…

系统学习redis之二——redis集群搭建

redis单点部署&#xff1a; 安装命令&#xff1a; # cd /usr/local/ # wget http://download.redis.io/releases/redis-4.0.1.tar.gz #下载安装包 # yum -y install gcc psmisc #安装依赖包 # tar xf redis-4.0.1.tar.gz # cd /usr/lo…