OC对象分类
OC对象分类
OC对象分类
OC对象分类:instance对象(实例对象)、class对象(类对象)、meta-class对象(元类对象);
instance对象#
定义:通过类alloc出来的对象,就是instance对象,每次调用alloc都会产生新的instance对象;
instance对象在内存中存储的信息包括:
- isa指针;
- 其它成员变量;
class对象#
注意:每个类对象在内存中都是唯一的(只有一份),每个类只有一个元类
获取类对象:[obj class]、object_getClass(obj);
class对象在内存中存储的信息包括:
meta-class对象和class对象的内存结构是一样的,但是用途不一样,在内存中包括的信息主要如下:
- ias指针;
- superclass指针;
- 类的属性信息(@property)、类的对象方法信息(instance method)
- 类的协议信息(protocol)、类的成员变量信息(ivar)。
- 类方法也是放在元类里面的;
meta-class对象#
获得元类对象:
//将类对象当做参数传入,获得元类对象:
Class metaClass = object_getClass([NSObject class]);
判定一个对象是不是元类:
class_isMetaClass(obj);
获取类对象、元类对象的三个方法的区别:
-
object_getClass([NSObject class]);
- 传入字符串类名,返因对应的类对象;
-
object_getClass(obj)
- 传入的obj可能是instance对象,class对象、meta-class对象;
- 返回:
- 如果传的是instance对象,返回class对象;
- 如果传的是class对象,返回meta-class对象;
- 如果传的是meta-class对象,返回的是NSObject(基类)的meta-class对象;
-
-(Class)class 、+(Class)class
返回的就是类对象
isa指针:存放那些信息?#
-
实例对象(instance):
isa、其它成员变量;
-
类对象(class):
isa、superclass、属性、对象方法、协议、成员变量;
-
meta-class:
isa、superclass、类方法
instance的isa指向class(类对象):当调用对象方法时,通过instance的isa找到class,最后找到对象的方法实现进行调用;
class的isa指向meta-class:当调用类方法时,通过class的isa找到meta-class,最后找到类方法的实现进行调用;**
meta-class的isa指向基类有meta-class
class的superclass指向父类的class,如果没有父类,superclass指针为nil;
meta-class的superclass指向的是父类的meta-class
注意:由于NSObject没有superclass,但也不是为空,而是:基类的meta-class对象的superclass指向的是基类的class(类对象)(如下图三),
按上面的流程,举个例分析说明:
Student *stu = [[Student alloc] init];
[stu test];//调用对象方法
[stu classTest];//调用类方法
stu调用
test
的调用流程:首先test是对象方法,而对象方法是放在class里面,
流程:通过stu通过自己的isa找到他自己的class,在class对象中找test方法,如果有就展开调用,如果没有class通过isa去superclass的里面找(一层层的往上找,直到继承关系走完),如果还没有,superclass通过自己的isa去meta-class里面找,最后走到NSObject,如果还是没有找到就会报错:"unreconized selector sent to instance"
注意:如果在调用类方法classTest
,因找不到方法崩溃之前,其实还有最后一步流程,也是我们一般没注意的地方,在基类的meta-class对象找不到classTest
方法时,它还会去基类的类对象里面找(即上图右上角转角那个箭头),如果则调用,否则才报错。可能你觉得很奇怪,meta-class里面存放的是类方法,类里面存放的是对象方法,为什么meta-class类对象里面找不到方法时会找到类的对象方法里面去?具体这个根runtime机制有关,后面有时间我会写runtime相关的问题;
可以进行如下测试:
@implementation NSObject (Test)
+ (void)test {
NSLog(@"+[NSObject test] - %p", self);
}
- (void)test {
NSLog(@"-[NSObject test] - %p", self);
}
@end
// Person
@interface Person : NSObject
- (void)test;
@end
@implementation Person
- (void)test {
NSLog(@"+[Person test] - %p", self);
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"[Person class] - %p", [Person class]);
NSLog(@"[NSObject class] - %p", [NSObject class]);
[Person test];
[NSObject test];
}
return 0;
}
上面我们在NSObject类扩展中申明和实现了一个实例方法,调用的时候调用的是类方法,但你会神奇的发现不会崩溃,而且调用者分别是Person、NSObject;其实就是我们上面所说到的在基类的meta-class对象找不到test
方法时,它还会去基类的类对象里面找.
结论:#
对象的isa指针指向哪里?#
- instance对象的isa指向class对象;
- class对象的isa指向meta-class对象;
- meta-class对象的isa指向基类的meta-class对象
OC的类信息存放在哪里?#
- **对象方法、属性、成员变量、协议信息,存放在class对象中;
- 类方法,存放在meta-class对象中;
- 成员变量的具体值,存放在instance对象;
窥探struct objc_class结构体#
从objc_runtime源码得到如下结构图:
已经编译好一个从objc_runtime源码抽出来工程,可以清楚看到objc_class的内部结构:
代码地址:[窥struct objc_class结构体](
作者: 热血文码士
出处:https://www.cnblogs.com/nenhall/p/16264967.html
版权:本文采用「署名-非商业性使用-相同方式共享 4.0 国际」知识共享许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)