了解objective-C语言对象模型中对 isa swizzling 和method swizzling 的支持,
isa 指针
在 Objective-C面向对象语言中,每一个对象都是一个类的示例,实例中包含一个 isa 指针,指向的是对象所属的类
@interface NSObject <NSObject> {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
Class isa OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}
/// Represents an instance of a class.
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
Class 是什么?
在objc.h 文件中找到class 的定义
/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;
从上面源码中可以看出来 Class 就是一个 objc_class * 结构体指针类型
按住cmd键点击 objc_class 进入 runtime.h 中可以看见如下 objc_class 的定义
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE;
const char * _Nonnull name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */
mateClass(元类)
从上面 objc_class 结构体中可以发现其中也包含一个 isa 指针,在Objective-C语言设计中,类也是对象,它属于另一个类的示例对象,而这里的另一个类所指的就是元类(mateClass),元类里面保存了类的对象方法列表。元类也是一个,也就是说元类也是一个对象,其中也包含一个 isa 指针,isa 指针所指向的是根元类(root MateClass),根元类的 isa 指针指向的是根元类的本身,这样使得 Objective-C 语言在设计上就形成了一个闭环。
Class(类)、MateClass(元类)继承关系
前面说过,示例方法保存在类中,类方方法保存在元类中,根据对象在调用方法的时候,如果类中没有方法的实现,则会想它的父类继续查找。为了保证这一点,子类继承父类,子类的元类继承父类的元类。如下图所示:
- 实线表示继承
- 虚线表示 isa 指向
属性列表
对象方法列表
方法列表存放 objc_class 结构体的 methodLists 中,methodLists 为 objc_method_list 结构体类型,如下是 objc_method_list 的定义,
struct objc_method_list {
struct objc_method_list * _Nullable obsolete OBJC2_UNAVAILABLE;
int method_count OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
/* variable length structure */
struct objc_method method_list[1] OBJC2_UNAVAILABLE;
} OBJC2_UNAVAILABLE;
方法存储在 method_list ,进一步查看 objc_method 的定义
struct objc_method {
SEL _Nonnull method_name OBJC2_UNAVAILABLE;
char * _Nullable method_types OBJC2_UNAVAILABLE;
IMP _Nonnull method_imp OBJC2_UNAVAILABLE;
}
方法列表与分类方法的关系
对象模型的应用
KVO
用一个例子来开始吧
- 新建一个名为 KVOTest
@interface KVOTest : NSObject <TestProtocol>
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, assign) NSInteger h;
+ (void)test;
- (void)test;
@end
- 创建示例对象
@interface ViewController ()
@property (nonatomic, strong) KVOTest *test;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.test = [[KVOTest alloc] init];
self.test.age = 50;
id class = object_getClass(self.test);
NSLog(@">>>>>>class1:%@", class);
NSLog(@">>class:%@", self.test.class);
[self.test addObserver:self forKeyPath:@"age" options:(NSKeyValueObservingOptions)NSKeyValueChangeNewKey context:nil];
id class1 = object_getClass(self.test);
NSLog(@">>>>>>class1:%@", class1);
NSLog(@">>class:%@", self.test.class);
[self.test addObserver:self forKeyPath:@"h" options:(NSKeyValueObservingOptions)NSKeyValueChangeNewKey context:nil];
id class2 = object_getClass(self.test);
NSLog(@">>class:%@", self.test.class);
NSLog(@">>>>>>class1:%@", class2);
id MetaClass = objc_getMetaClass("KVOTest");
NSLog(@"MetaClass :%@",MetaClass);
// d输出继承链
while (class1) {
class1 = class_getSuperclass(class1);
NSLog(@">>%@",class1);
}
}
- 输出结果
2019-08-09 17:38:50.193966+0800 KVOTest[13656:155097] >>>>>>class1:KVOTest
2019-08-09 17:38:50.194123+0800 KVOTest[13656:155097] >>class:KVOTest
2019-08-09 17:38:50.194560+0800 KVOTest[13656:155097] >>>>>>class1:NSKVONotifying_KVOTest
2019-08-09 17:38:50.194669+0800 KVOTest[13656:155097] >>class:KVOTest
2019-08-09 17:38:50.194902+0800 KVOTest[13656:155097] >>class:KVOTest
2019-08-09 17:38:50.194996+0800 KVOTest[13656:155097] >>>>>>class1:NSKVONotifying_KVOTest
2019-08-09 17:38:50.195088+0800 KVOTest[13656:155097] MetaClass :KVOTest