What is a meta-class in Objective-C?
http://www.cocoawithlove.com/2010/01/what-is-meta-class-in-objective-c.html
In this post, I look at one of the stranger concepts in Objective-C — the meta-class. Every class in Objective-C has its own associated meta-class but since you rarely ever use a meta-class directly, they can remain enigmatic. I'll start by looking at how to create a class at runtime. By examining the "class pair" that this creates, I'll explain what the meta-class is and also cover the more general topic of what it means for data to be an object or a class in Objective-C.
Creating a class at runtime
The following code creates a new subclass of NSError
at runtime and adds one method to it:
Class newClass =
objc_allocateClassPair([NSError class], "RuntimeErrorSubclass", 0);
class_addMethod(newClass, @selector(report), (IMP)ReportFunction, "v@:");
objc_registerClassPair(newClass);
The method added uses the function named ReportFunction
as its implementation, which is defined as follows:
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]));
}
On the surface, this is all pretty simple. Creating a class at runtime is just three easy steps:
- Allocate storage for the "class pair" (using
objc_allocateClassPair
). - Add methods and ivars to the class as needed (I've added one method using
class_addMethod
). - Register the class so that it can be used (using
objc_registerClassPair
).
However, the immediate question is: what is a "class pair"? The function objc_allocateClassPair
only returns one value: the class. Where is the other half of the pair?
I'm sure you've guessed that the other half of the pair is the meta-class (it's the title of this post) but to explain what that is and why you need it, I'm going to give some background on objects and classes in Objective-C.
What is needed for a data structure to be an object?
Every object has a class. This is a fundamental object-oriented concept but in Objective-C, it is also a fundamental part of the data. Any data structure which has a pointer to a class in the right location can be treated as an object.
In Objective-C, an object's class is determined by its isa
pointer. The isa
pointer points to the object's Class.
In fact, the basic definition of an object in Objective-C looks like this:
typedef struct objc_object {
Class isa;
} *id;
What this says is: any structure which starts with a pointer to a Class
structure can be treated as an objc_object
.
The most important feature of objects in Objective-C is that you can send messages to them:
[@"stringValue"
writeToFile:@"/file.txt" atomically:YES encoding:NSUTF8StringEncoding error:NULL];
This works because when you send a message to an Objective-C object (like the NSCFString
here), the runtime follows object's isa
pointer to get to the object's Class
(the NSCFString
class in this case). The Class
then contains a list of the Method
s which apply to all objects of that Class
and a pointer to the superclass
to look up inherited methods. The runtime looks through the list of Method
s on the Class
and superclasses to find one that matches the message selector (in the above case, writeToFile:atomically:encoding:error
on NSString
). The runtime then invokes the function (IMP
) for that method.
The important point is that the Class
defines the messages that you can send to an object.
What is a meta-class?
Now, as you probably already know, a Class
in Objective-C is also an object. This means that you can send messages to a Class
.
NSStringEncoding defaultStringEncoding = [NSString defaultStringEncoding];
In this case, defaultStringEncoding
is sent to the NSString
class.
This works because every Class
in Objective-C is an object itself. This means that the Class
structure must start with an isa
pointer so that it is binary compatible with the objc_object
structure I showed above and the next field in the structure must be a pointer to the superclass
(or nil
for base classes).
As I showed last week, there are a couple different ways that a Class
can be defined, depending on the version of the runtime you are running, but yes, they all start with an isa
field followed by a superclass
field.
typedef struct objc_class *Class;
struct objc_class {
Class isa;
Class super_class;
/* followed by runtime specific details... */
};
However, in order to let us invoke a method on a Class
, the isa
pointer of the Class
must itself point to a Class
structure and that Class
structure must contain the list of Method
s that we can invoke on the Class.
This leads to the definition of a meta-class: the meta-class is the class for a Class
object.
Simply put:
- When you send a message to an object, that message is looked up in the method list on the object's class.
- When you send a message to a class, that message is looked up in the method list on the class' meta-class.
The meta-class is essential because it stores the class methods for a Class
. There must be a unique meta-class for every Class
because every Class
has a potentially unique list of class methods.
What is the class of the meta-class?
The meta-class, like the Class
before it, is also an object. This means that you can invoke methods on it too. Naturally, this means that it must also have a class.
All meta-classes use the base class' meta-class (the meta-class of the top Class
in their inheritance hierarchy) as their class. This means that for all classes that descend from NSObject
(most classes), the meta-class has the NSObject
meta-class as its class.
Following the rule that all meta-classes use the base class' meta-class as their class, any base meta-classes will be its own class (their isa
pointer points to themselves). This means that the isa
pointer on the NSObject
meta-class points to itself (it is an instance of itself).
Inheritance for classes and meta-classes
In the same way that the Class
points to the superclass with its super_class
pointer, the meta-class points to the meta-class of the Class
' super_class
using its own super_class
pointer.
As a further quirk, the base class' meta-class sets its super_class
to the base class itself.
The result of this inheritance hierarchy is that all instances, classes and meta-classes in the hierarchy inherit from the hierarchy's base class.
For all instances, classes and meta-classes in the NSObject
hierarchy, this means that all NSObject
instance methods are valid. For the classes and meta-classes, all NSObject
class methods are also valid.
All this is pretty confusing in text. Greg Parker has put together an excellent diagram of instances, classes, meta-classes and their super classes and how they all fit together.
Experimental confirmation of this
To confirm all of this, let's look at the output of the ReportFunction
I gave at the start of this post. The purpose of this function is to follow the isa
pointers and log what it finds.
To run the ReportFunction
, we need to create an instance of the dynamically created class and invoke the report
method on it.
id instanceOfNewClass =
[[newClass alloc] initWithDomain:@"someDomain" code:0 userInfo:nil];
[instanceOfNewClass performSelector:@selector(report)];
[instanceOfNewClass release];
Since there is no declaration of the report
method, I invoke it using performSelector:
so the compiler doesn't give a warning.
The ReportFunction
will now traverse through the isa
pointers and tell us what objects are used as the class, meta-class and class of the meta-class.
Getting the class of an object: the
ReportFunction
usesobject_getClass
to follow theisa
pointers because theisa
pointer is a protected member of the class (you can't directly access other object'sisa
pointers). TheReportFunction
does not use theclass
method to do this because invoking theclass
method on aClass
object does not return the meta-class, it instead returns theClass
again (so[NSString class]
will return theNSString
class instead of theNSString
meta-class).
This is the output (minus NSLog
prefixes) when the program runs:
This object is 0x10010c810.
Class is RuntimeErrorSubclass, and super is NSError.
Following the isa pointer 1 times gives 0x10010c600
Following the isa pointer 2 times gives 0x10010c630
Following the isa pointer 3 times gives 0x7fff71038480
Following the isa pointer 4 times gives 0x7fff71038480
NSObject's class is 0x7fff710384a8
NSObject's meta class is 0x7fff71038480
Looking at the addresses reached by following the isa
value repeatedly:
- the object is address
0x10010c810
. - the class is address
0x10010c600
. - the meta-class is address
0x10010c630
. - the meta-class's class (i.e. the
NSObject
meta-class) is address0x7fff71038480
. - the
NSObject
meta-class' class is itself.
The value of the addresses is not really important except that it shows the progress from class to meta-class to NSObject
meta-class as discussed.
Conclusion
The meta-class is the class for a Class
object. Every Class
has its own unique meta-class (since every Class
can have its own unique list of methods). This means that all Class
objects are not themselves all of the same class.
The meta-class will always ensure that the Class
object has all the instance and class methods of the base class in the hierarchy, plus all of the class methods in-between. For classes descended from NSObject
, this means that all the NSObject
instance and protocol methods are defined for all Class
(and meta-class) objects.
All meta-classes themselves use the base class' meta-class (NSObject
meta-class for NSObject
hierarchy classes) as their class, including the base level meta-class which is the only self-defining class in the runtime.
What is a meta-class in Objective-C?的更多相关文章
- 刨根问底Objective-C Runtime
http://chun.tips/blog/2014/11/05/bao-gen-wen-di-objective%5Bnil%5Dc-runtime-(2)%5Bnil%5D-object-and- ...
- Objective-C--Runtime机制
个人理解: 简单来说,Objective-C runtime是一个实现Objective-C语言的C库.对象可以用C语言中的结构体表示,而方法(methods)可以用C函数实现.事实上,他们 差不多也 ...
- IOS-RunTime(刨根问底)
方法调用 让我们看一下方法调用在运行时的过程(参照前文类在runtime中的表示) 如果用实例对象调用实例方法,会到实例的isa指针指向的对象(也就是类对象)操作.如果调用的是类方法,就会到类对象的i ...
- Automake
Automake是用来根据Makefile.am生成Makefile.in的工具 标准Makefile目标 'make all' Build programs, libraries, document ...
- The Rise of Meta Learning
The Rise of Meta Learning 2019-10-18 06:48:37 This blog is from: https://towardsdatascience.com/the- ...
- 常用 meta 整理
<!-- 针对手持设备优化,主要是针对一些老的不识别viewport的浏览器,比如黑莓 --> <meta name="HandheldFriendly" con ...
- meta标签
参考:http://www.jb51.net/web/158860.html META标签分两大部分:HTTP标题信息(HTTP-EQUIV)和页面描述信息(NAME). 一.HTTP标题信息(HTT ...
- Django模型类Meta元数据详解
转自:https://my.oschina.net/liuyuantao/blog/751337 简介 使用内部的class Meta 定义模型的元数据,例如: from django.db impo ...
- H5 meta小结
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1, ...
- Asp.net 后台添加CSS、JS、Meta标签
Asp.net 后台添加CSS.JS.Meta标签的写法,我这里写成函数方便以后使用.如果函数放在页面类中, Page参数也可以不要. 首先导入命名空间 using System.Web.UI.Htm ...
随机推荐
- Linux下的eclipse的安装
其实在linux里配好java环境后,就已经好了. 从官网下一个eclipse,解压后,就可以直接执行eclipse了,实在是不知道什么是安装. 其实在配置java时,也是一样. 可见在linux下, ...
- java继承使用的细节问题?
关于java继承的基本概念就不多说了,下面就说说继承使用应该注意的细节问题? 示例 一: package com.bizvane; class Fu{ public Fu() { System.out ...
- 特性attribute,声明和使用attribute,应用attribute,AOP面向切面,多种方式实现AOP
1 特性attribute,和注释有什么区别2 声明和使用attribute3 应用attribute4 AOP面向切面5 多种方式实现AOP ---------------------------- ...
- Unite 2017 干货整理 优化篇
Unite 2017 干货整理 优化篇 2017年05月16日 将Unite 2017的一些演讲做了整理. 本篇有内存,CPU.GC.UI.渲染性能指标.Tips几个小节. 内容持续整理中. 内存 ...
- Spark 中的 checkpoint
为了实现容错,需要做checkpoint.以Streaming为例,checkpoint中有两种数据: 1. Metadata checkpointing:用于恢复driver端出错的情况.其中包含: ...
- 小a和uim之大逃离(luogu P1373 dp)
小a和uim之大逃离(luogu P1373 dp) 给你一个n*m的矩阵,其中元素的值在1~k内.限制只能往下和往右走,问从任意点出发,到任意点结束,且经过了偶数个元素的合法路径有多少个.在此题中, ...
- QQ 数(number.pas/c/cpp)——莫比乌斯函数
题目 [问题描述] 企鹅国数学家 QQ 潜心研究数论,终于发现了一个简单的数论问题! 一个 QQ 数定义为一个拥有一个大于 $ 1 $ 的完全平方数为因子的数字,一个数字的 QQ 值定义为这个数是 Q ...
- 安卓下点击a标签不跳转;点击a标签在手机真机上会调出手机键盘的解决办法
安卓下点击a标签不跳转的解决办法,是不用href做跳转的链接,改为用JS控制跳转 <a href="javascript:;" ontouchstart="wind ...
- js 中止程序继续进行(break continue return throw)
1.break 跳出循环 2.continue 跳出本次循环,进入下次循环 3.return 中止当前函数继续执行 4.throw 异常信息;中止程序抛出异常,可用于中止程序
- [Android]Android性能优化
安卓性能优化 性能优化的几大考虑 Mobile Context 资源受限 + 内存,普遍较小,512MB很常见,开发者的机器一般比用户的机器高端 + CPU,核心少,运算能力没有全开 + GPU,上传 ...