iOS-OC|iOS-class方法和objc_getClass方法
根据上一篇博客iOS-class、object_getClass、objc_getClass、objc_getMetaClass区别的研究发现,发现主要还是class方法和objc_getClass方法的区别,因此本篇文章主要讲述一下class方法和objc_getClass方法。
一、Object(objc实例对象),Class(类),Metaclass(元类),Rootclass(根类),Rootclass‘s metaclass(根元类) 首先说下Objective-C中类的几种数据结构;在Objective-C的类型结构中,Object(实例),Class(类),Metaclass(元类),Rootclass(根类),Rootclass‘s metaclass(根元类),且这些都是对象。
我们可用过两张图了解一下上述类型中的关系图
1、经典的Objective-C的对象模型图
文章图片
2、 实例对象(Object),类(CLass),元类(Metaclass)之间的关系
文章图片
实例对象(Object): 我们创建的一个对象或实例objc其实就是一个struct objc_object
结构体,这个结构体只有一个成员变量,这是一个Class
类型的变量isa
,也是一个结构体指针,这个objc对象的isa指针指向他的类对象(即平时我们所说的类)
类(CLass):存储Object实例的相关数据,如:实例方法列表、成员变量列表、属性列表。
元类(Metaclass):存储Class相关的数据,如:类方法列表、类的信息等。
参考苹果官方公开源码
objc4源码在线浏览
objc4源码下载
二、class方法和objc_getClass方法
1、class方法
实例方法 - (CLass)class;
类方法 + (Classs)class
在苹果公开的官方objc源码,NSObject.mm文件中:
// 类方法,返回自身
+ (Class)class {
return self;
}
// 实例方法,查找isa(类)
- (Class)class {
return object_getClass(self);
}
2、object_getClass方法
object_getClass(id _Nullable obj)
(1)传入参数:obj可能是instance对象、class对象、meta-class对象
(2)返回值:
【1】如果是instance对象,返回class对象
【2】如果是class对象,返回meta-class对象
【3】如果是meta-class对象,返回NSObject(基类)的meta-class对象
官方源码:
/***********************************************************************
* object_getClass.
* Locking: None. If you add locking, tell gdb (rdar://7516456).
**********************************************************************/
Class object_getClass(id obj)
{
if (obj) return obj->getIsa();
else return Nil;
}
三、objc对象类型 我们首先通过objc_getClass方法获取isa指针,即指向类对象的指针
objc_getMetaClass方法获取类对象中的isa指针,即指向元类对象的指针
代码如下:
Class c1 = objc_getClass("People");
Class c2 = objc_getMetaClass("People");
NSLog(@"objc_getClass----%p",c1);
NSLog(@"objc_getMetaClass----%p",c2);
输出结果:
文章图片
1、obj为实例对象
在Object-C中,Object本质上是一个struct,在这个struct中会保存一个名为isa的指针,该指针会指向该Object的类。定义如下所示:
/// Represents an instance of a class.
struct objc_object {
Class _Nonnull isaOBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
我们初始化一个类的实例可以直接用
id
来定义,那么id
就是上面这样定义的,所以类的实例初始化完了之后,它的内部就多了一个isa
指针,这个指针类型指向的是struct objc_class的
结构体,其实也就是指向了这个实例所属的类。代码如下:
//obj为实例对象
id obj = [[People alloc]init];
People *people = obj;
/*----obj为实例对象----*/
Class cls = [obj class];
Class cls2 = object_getClass(obj);
Class cls3 = [people class];
Class cls4 = object_getClass(people);
NSLog(@"");
NSLog(@"----obj为实例对象----");
NSLog(@"实例对象:class----%p" , cls);
NSLog(@"实例对象:object_getClass----%p" , cls2);
NSLog(@"实例对象:class----%p" , cls3);
NSLog(@"实例对象:object_getClass----%p" , cls4);
输出结果:
文章图片
当obj为实例变量时
object_getClass(obj)与[obj class]输出结果一直,均获得isa指针,即指向类对象的指针。
2、obj为Class类对象
在Objective-C中,任何类的定义都是对象(除了int、char等这些基本类型)。类和类的实例(对象)没有任何本质上的区别。任何对象都有isa指针。
我们打开Xcode中 <
obc/runtime.h
> 头文件或者苹果公开的objc官方源码runtime.h文件中,里面有一个结构体定义struct object_class{
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_classOBJC2_UNAVAILABLE;
// 父类
const char *nameOBJC2_UNAVAILABLE;
// 类名
long versionOBJC2_UNAVAILABLE;
// 类的版本信息,默认为0
long infoOBJC2_UNAVAILABLE;
// 类信息,供运行期使用的一些位标识
long instance_sizeOBJC2_UNAVAILABLE;
// 该类的实例变量大小
struct objc_ivar_list *ivarsOBJC2_UNAVAILABLE;
// 该类的成员变量链表
struct objc_method_list *methodListsOBJC2_UNAVAILABLE;
// 方法定义的链表
struct objc_cache *cacheOBJC2_UNAVAILABLE;
// 方法缓存
struct objc_protocol_list *protocolsOBJC2_UNAVAILABLE;
// 协议链表
#endif
}OBJC2_UNAVAILABLE;
这个结构体其实就是我们所说的 类,他的
Class isa
这个指针的类型点进去会发现,定义如下:// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;
原来isa指针指向的依然是个
objc_class
结构体,只不过为了语义化起个名字叫Class
代码如下:
//obj为实例对象
id obj = [[People alloc]init];
People *people = obj;
//classObj为类对象
Class classObj = [obj class];
/*----obj为类对象----*/
Class clsc = [classObj class];
Class clsc2 = object_getClass(classObj);
NSLog(@"");
NSLog(@"----obj为类对象----");
NSLog(@"类对象:class----%p" , clsc);
NSLog(@"类对象:object_getClass----%p" , clsc2);
输出结果:
文章图片
当obj为类对象时
object_getClass(obj)返回类对象中的isa指针,即指向元类对象的指针;
[obj class]返回的则是类对象其本身
3、obj为Metaclass类(元类)对象
Metaclass元类与Class的结构是一样的,只是职能不同。
类(CLass):存储Object实例的相关数据,如:实例方法列表、成员变量列表、属性列表。
元类(Metaclass):存储Class相关的数据,如:类方法列表、类的信息等。我们可以参考头部实例对象(Object),类(CLass),元类(Metaclass)之间的关系图解
代码如下:
//obj为实例对象
id obj = [[People alloc]init];
//classObj为类对象
Class classObj = [obj class];
//metaClassObj为元类对象
Class metaClassObj = object_getClass(classObj);
/*----obj为元类对象----*/
Class clso = [metaClassObj class];
Class clso2 = object_getClass(metaClassObj);
NSLog(@"");
NSLog(@"----obj为元类对象----");
NSLog(@"元类对象:class----%p" , clso);
NSLog(@"元类对象:object_getClass----%p" , clso2);
输出结果:
文章图片
当obj为Metaclass(元类)对象时
object_getClass(obj)返回元类对象中的isa指针,因为元类对象的isa指针指向根类,所有返回的是根类对象的地址指针;
[obj class]返回的则是元类本身
4、obj为Rootclass类(根类)对象
Rootclass就是根类,任何类的Metaclass中的isa指针都是指向根类。且结构与Class结构是一样的。
代码如下:
//obj为实例对象
id obj = [[People alloc]init];
//classObj为类对象
Class classObj = [obj class];
//metaClassObj为元类对象
Class metaClassObj = object_getClass(classObj);
//rootClassObj为根类对象
Class rootClassObj = object_getClass(metaClassObj);
/*----obj为根类对象----*/
Class clsr = [rootClassObj class];
Class clsr2 = object_getClass(rootClassObj);
NSLog(@"");
NSLog(@"----obj为根类对象----");
NSLog(@"根类对象:class----%p" , clsr);
NSLog(@"根类对象:object_getClass----%p" , clsr2);
输出结果:
文章图片
当obj为Rootclass(根类)对象时
object_getClass(obj)返回根类对象中的isa指针,因为根类对象的isa指针指向Rootclass‘s metaclass(根元类),即返回的是根元类的地址指针;
[obj class]返回的则是其本身。
因为根类的isa指针其实是指向本身的,所有根元类其实就是根类,所有输出的结果是一样的。
四、结论 1、object_getClass(obj)
返回的是obj的isa指针
2、[obj class]
(1)obj为实例对象
调用的是实例方法:
- (Class)class
,返回的obj对象中的isa指针;(2)obj为类对象(包括元类和根类以及根元类)
调用的是类方法:
+ (Class)class
,返回的结果为调用者本身。这时候我们再回过头看看Object-C的对象模型图,思考一下会发现
1、内存创建一个instance实例对象(People *people),同时会创建一个与之对应的类对象(Class peopleClass)和元类对象(Class peopleMeta);
注:实例对象通过calloc可创建多个,但类对象和元类对象在内存中只有一份,只创建一次;
2、对象的本质,其实是C语言的结构体struct,各个对象的内存结构为:
people:isa指针+仅存储Person类成员变量的值;
People:isa指针+superclass指针+存储成员变量的类型、名称,协议,对象方法等;
peopleMeta:isa指针+superclass指针+仅存储类方法;
3、isa指向:
people:指向类对象People;
People:指向元类对象peopleMeta;
peopleMeta:指向基类(Root,如:NSObject)的元类对象meta(基类的元类对象的isa指向该元类对象自己);
4、superclass指向:
People:指向父类>>基类的类对象指向nil;
peopleMeta:指向父类>>基类的元类对象指向该基类的类对象;
GitHub示例代码Demo
参考文章:
iOS笔记--class方法和objc_getClass方法
【iOS-OC|iOS-class方法和objc_getClass方法】object_getClass(obj)与[obj class]的区别
class和object_getClass方法区别
推荐阅读
- 对抗抑郁最好的方法
- 怎样用黑谜速冻膜去黑头,|怎样用黑谜速冻膜去黑头, 最有效的去黑头的方法看这!
- 移动端h5调试方法
- 唱歌教学(导致嗓音损坏的几个常见的错误唱歌方法!)
- 拆书方法训练营
- 数组常用方法一
- 这份史上最经典的3大学习方法,清华北大学霸都在用!
- 迅捷流程图制作软件的使用方法!
- VueX--VUE核心插件
- 15个从现实焦虑中恢复精神的方法!