上一篇文章咱们学习过对象本质以后,咱们知道对象内部有一个isa指针,本文将描述对象的分类,学习完以后,须要咱们回答如下几个问题:bash
OC中有三种对象,咱们将依次讨论,它们分别是:架构
instance 是实例对象,经过alloc 出来的对象,每次调用alloc都会产生新的instance对象。学习
NSObject *obj1 = [[NSObject alloc] init];
NSObject *obj2 = [[NSObject alloc] init];
// obj一、obj2都是instance对象
复制代码
obj一、obj2是NSObject的instance对象,它们是不一样的两个对象,分别占据着两块不一样的内存空间。ui
instance 对象在内存中存储的信息有:atom
class是类对象,在内部中存储的信息包括:spa
NSObject *object1 = [[NSObject alloc] init];
NSObject *object2 = [[NSObject alloc] init];
Class objectClass1 = [object1 class];
Class objectClass2 = object_getClass(object1);
Class objectClass3 = [NSObject class];
Class objectClass4 = objc_getClass("NSObject");
Class objectClass5 = [object2 class];
Class objectClass6 = object_getClass(object2);
NSLog(@"%p-%p-%p-%p-%p-%p", objectClass1, objectClass2,
objectClass3, objectClass4, objectClass5, objectClass6);
//0x7fff9da14118-0x7fff9da14118-0x7fff9da14118-0x7fff9da14118-0x7fff9da14118-0x7fff9da14118
复制代码
经过 [object1 class]
或者 NSObject class]
或者 object_getClass(object1)
三个方法获取class对象。3d
//获取元类
Class objectMetaClass = object_getClass([NSObject class]);
复制代码
meta-class对象内部中存储的信息包括:指针
class
与meta-class
的内存结构是同样的,都是Class(struct objc_class结构体)日志
注意:code
Class objectClass = [[NSObject class] class]; //返回的class对象,不管调用多少次class方法,返回的都是class对象。
object_getClass(obj1); //若是参数是instance对象,则返回class对象
//若是参数是class对象,则返回meta-class对象
//若是是meta-class对象,返回NSObject(基类)的meta-class对象
object_getClass([NSObject class]);
//查看Class是不是meta-class
BOOL isMetaClass = class_isMetaClass([NSObject class]);
//返回参数对应的class对象。
Class class = objc_getClass("NSObject");
复制代码
了解了instance、class、metaclass的结构以后,咱们看一下,isa指针和superclass指针。instance、class、metaclass内部都含有isa指针,而只有class、metaclass内部含有suerclass指针。
下面咱们建立两个类Person
与 Student
其中,Student
继承自Person
。
Person类
@interface Person : NSObject<NSCopying> {
@public
int _age;
}
@end
@implementation Person
- (void)personInstanceMethod {
}
+ (void)personClassMethod {
}
- (nonnull id)copyWithZone:(nullable NSZone *)zone {
return nil;
}
@end
复制代码
Student类
@interface Student : Person<NSCoding>
@end
@implementation Student
- (void)studentInstanceMethod {
}
+ (void)studentClassMethod {
}
- (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder {
return nil;
}
- (void)encodeWithCoder:(nonnull NSCoder *)coder {
}
- (nonnull id)copyWithZone:(nullable NSZone *)zone {
return nil;
}
@end
复制代码
而后咱们分析以下调用:
Student *student = [[Student alloc] init];
// 实例(instance)对象,调用类(class)方法。
// 先经过实例对象student的isa指针找到Student类对象
// 再在Student类对象内部找到studentInstanceMethod方法,并触发调用
[student studentInstanceMethod];// -> objc_msgSend(student, studentClassMethod);
// 先经过实例对象student的isa指针找到Student类对象
// 再在Student类对象内部查找personInstanceMethod,没有找到。
// 经过Student类对象的superclass指针查找到Person类对象,在其内部找到personInstanceMethod方法,并触发调用
[student personInstanceMethod];// -> objc_msgSend(student, personInstanceMethod);
// 类(class)对象调用类方法。
//在Student类对象内部查找studentClassMethod方法,找到并触发调用
[Student studentClassMethod]; // -> objc_msgSend([Student class], studentClassMethod);
//在Student类对象内部查找personClassMethod方法,没有找到
//经过Student类对象的superclass指针,找到Person类对象,
//在其内部找到personClassMethod,并触发调用。
[Student personClassMethod]; // -> objc_msgSend([Student class], personClassMethod);
复制代码
经过分析,咱们得出以下结论:
经过上面的分析,咱们画出以下isa与superclass的指向图,以下:
在上图中,有一条特殊的线,基类的metaclass的superclass指针指向的不是nil,而是基类的class对象。咱们证明一下。
咱们给NSObject对象增长一个分类,在分类中增长一个实例方法,以下:
@interface NSObject (test)
- (void)test;
@end
@implementation NSObject (test)
- (void)test{
NSLog(@"-NSObject (test)");
}
@end
复制代码
经过上面的学习,咱们知道-test
是在NSObject的class对象内部实现的。
而后咱们实现Person类,Person类只是基础NSObject。
//
// main.m
// Class对象
//
// Created by MrLi on 2020/5/16
// Modified by MrLi
// Copyright © 2020 MrLi. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import "NSObject+test.h"
@interface Person : NSObject<NSCopying>
@end
@implementation Person
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
[Person test];
}
return 0;
}
复制代码
咱们在main方法直接调用[Person test]
。它的调用轨迹是:
理论上,instance的isa指针指向的内容应该是class的地址,class的isa指针指向的内容应该是metaclass的地址。但其实它是经过& ISA_MASK
计算出来的。
在不一样的架构下 ISA_MASK
取值不一样。以下
# if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# elif __x86_64__
# define ISA_MASK 0x00007ffffffffff8ULL
复制代码
咱们看以下代码:
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@interface Student : Person<NSCoding>
@end
@implementation Student
@end
struct myclass {
Class isa;
Class superclass;
};
int main(int argc, const char * argv[]) {
@autoreleasepool {
Student *stu = [[Student alloc] init];
struct myclass *stuclass = (__bridge struct myclass*)([Student class]);
struct myclass *stumetaClass = (__bridge struct myclass*)object_getClass([Student class]);
NSLog(@"%p-%p-%p", stu, stuclass, stumetaClass);
NSLog(@"查看内存"); //断点
}
return 0;
}
复制代码
2020-05-17 17:02:06.481250+0800 Class对象[2250:1165673] 0x1031ab810-0x1000023e8-0x1000023c0
(lldb) p/x stu->isa
(Class) $0 = 0x001d8001000023e9 Student
(lldb) p/x 0x001d8001000023e9 & 0x00007ffffffffff8
(long) $1 = 0x00000001000023e8
(lldb) p/x stuclass->isa
(Class) $2 = 0x00000001000023c0
(lldb) p/x 0x00000001000023c0 & 0x00007ffffffffff8
(long) $3 = 0x00000001000023c0
(lldb) p/x stuclass->superclass
(Class) $4 = 0x0000000100002398 Person
(lldb) p/x [Person class]
(Class) $6 = 0x0000000100002398 Person
经过分析日志,咱们得出结论:
// objc4-781
struct objc_object {
Class _Nonnull isa;
};
struct objc_class : objc_object {
Class superclass;
cache_t cache;
class_data_bits_t bits; // 用户获取类的具体信息
}
struct class_rw_t {
uint32_t flags;
uint16_t witness;
explicit_atomic<uintptr_t> ro_or_rw_ext;
Class firstSubclass;
Class nextSiblingClass;
public:
// 获取ro
const class_ro_t *ro() const {
auto v = get_ro_or_rwe();
if (slowpath(v.is<class_rw_ext_t *>())) {
return v.get<class_rw_ext_t *>()->ro;
}
return v.get<const class_ro_t *>();
}
void set_ro(const class_ro_t *ro) {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
v.get<class_rw_ext_t *>()->ro = ro;
} else {
set_ro_or_rwe(ro);
}
}
// 获取methods
const method_array_t methods() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>()->methods;
} else {
return method_array_t{v.get<const class_ro_t *>()->baseMethods()};
}
}
//获取 properties
const property_array_t properties() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>()->properties;
} else {
return property_array_t{v.get<const class_ro_t *>()->baseProperties};
}
}
//获取 protocols
const protocol_array_t protocols() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>()->protocols;
} else {
return protocol_array_t{v.get<const class_ro_t *>()->baseProtocols};
}
}
};
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize; //
#ifdef __LP64__
uint32_t reserved;
#endif
const uint8_t * ivarLayout;
const char * name; // 类名
method_list_t * baseMethodList;
protocol_list_t * baseProtocols;
const ivar_list_t * ivars; //成员变量列表
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;
};
复制代码
至此,本文到此结束,还记得开篇的4个问题吗?想必你已经有了答案!