了解objective-C語言對象模型中對 isa swizzling 和method swizzling 的支持穆律,
isa 指針
在 Objective-C面向?qū)ο笳Z言中睡互,每一個對象都是一個類的示例愤估,實例中包含一個 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 * 結(jié)構(gòu)體指針類型
按住cmd鍵點擊 objc_class 進(jìn)入 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 結(jié)構(gòu)體中可以發(fā)現(xiàn)其中也包含一個 isa 指針蜓洪,在Objective-C語言設(shè)計中胯努,類也是對象牢裳,它屬于另一個類的示例對象,而這里的另一個類所指的就是元類(mateClass)叶沛,元類里面保存了類的對象方法列表蒲讯。元類也是一個,也就是說元類也是一個對象灰署,其中也包含一個 isa 指針判帮,isa 指針?biāo)赶虻氖歉悾╮oot MateClass),根元類的 isa 指針指向的是根元類的本身,這樣使得 Objective-C 語言在設(shè)計上就形成了一個閉環(huán)溉箕。
Class(類)晦墙、MateClass(元類)繼承關(guān)系
前面說過,示例方法保存在類中肴茄,類方方法保存在元類中晌畅,根據(jù)對象在調(diào)用方法的時候,如果類中沒有方法的實現(xiàn)寡痰,則會想它的父類繼續(xù)查找抗楔。為了保證這一點,子類繼承父類拦坠,子類的元類繼承父類的元類连躏。如下圖所示:
- 實線表示繼承
- 虛線表示 isa 指向
屬性列表
對象方法列表
方法列表存放 objc_class 結(jié)構(gòu)體的 methodLists 中,methodLists 為 objc_method_list 結(jié)構(gòu)體類型贞滨,如下是 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 ,進(jìn)一步查看 objc_method 的定義
struct objc_method {
SEL _Nonnull method_name OBJC2_UNAVAILABLE;
char * _Nullable method_types OBJC2_UNAVAILABLE;
IMP _Nonnull method_imp OBJC2_UNAVAILABLE;
}
方法列表與分類方法的關(guān)系
對象模型的應(yīng)用
KVO
用一個例子來開始吧
- 新建一個名為 KVOTest
@interface KVOTest : NSObject <TestProtocol>
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, assign) NSInteger h;
+ (void)test;
- (void)test;
@end
- 創(chuàng)建示例對象
@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);
}
}
- 輸出結(jié)果
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