截圖19.png
1.數(shù)據(jù)結構
(1)objc_object
截圖1.png
(2)objc_class
截圖2.png
(3)isa指針
截圖3.png
什么是isa指針?
isa分為指針型isa,isa的值代表class地址骇陈,非指針型isa的值的部分代表class的地址扫皱。
(4)isa指向
- 關于
對象
定罢,其指向類對象
截圖4.png - 關于
類對象
,其指向元類對象
截圖5.png
(5) catch_t
- 用于快速查找方法執(zhí)行的函數(shù)族购。
- 可
可增量擴展
的哈希表
結構 - 是
局部性原理的
最佳應用
其數(shù)據(jù)結構
如下圖
截圖6.png
(6) class_data_bits_t
-
class_data_bits_t
主要是對class_rw_t
的封裝 -
class_rw_t
代表了類相關的讀寫
信息,對class_ro_t的封裝
(7) class_rw_t
截圖7.png
(8) class_ro_t
截圖8.png
(9) method_t
截圖9.png
Type Encodings
- const char * types
截圖10.png
整體數(shù)據(jù)結構
圖11.png
2.對象、類對象抵拘、元類對象
-
類對象
存儲實例方法列表等信息 -
元類對象
存儲類方法列表等信息
截圖12.png
類對象和元類對象之間有什么區(qū)別和聯(lián)系哎榴?
實例對象可以通過isa指針
找到類對象,從而找到類對象中存儲的實例方法列表等信息僵蛛,類對 象可以通過isa指針
找到元類對象尚蝌,從而找到元類對象中存儲的類方法列表等信息,類對象和元類對象都是objc_class
這種數(shù)據(jù)結構的。對于任何一個元類對象充尉,它的isa指針都指向根元類對象飘言。根元類對象的superClass指針指向根類對象。
思考
調用一個類方法喉酌,會沿著元類對象及其元類對象的父類的方法列表依次查找热凹,當類方法在元類對象中找不到時,就會找根類對象中泪电,同名的實例方法實現(xiàn)般妙。
消息傳遞過程
調用實例方法, 首先系統(tǒng)會根據(jù)當前實例的isa指針,找到對應的類對象相速,在類對象及其父類的方法列表中依次查找碟渺,直到找到根類對象,如果還是沒用找到突诬,就會走到消息的轉發(fā)流程苫拍。
調用類方法,系統(tǒng)會根據(jù)當前類的isa指針旺隙,找到對應的元類對象绒极,在元類對象及其元類對象的父類方法列表中依次查找,直到找到根元類蔬捷,如果根元類中也沒有垄提,就會到根類對象中查找同名的實例方法榔袋,如果最終還是沒找到就會走到消息的轉發(fā)流程。
3.消息傳遞
圖13.png
14.png
截圖15.png
#import "Phone.h"
@implementation Phone
- (instancetype)init{
self = [super init];
if (self) {
NSLog(@"%@",NSStringFromClass([self class]));
NSLog(@"%@",NSStringFromClass([super class]));
}
return self;
}
@end
最終的打印結構是一致的铡俐,都是Phone
(1)緩存查找
給定值SEL
凰兑,目標值是對應bucket_t
中的IMP
截圖16.png
首先根據(jù)方法選擇器,通過一個函數(shù)映射出bucket_t在數(shù)組中的位置审丘,這一步驟涉及到哈希查找吏够。哈希查找就是根據(jù)給定的一個值,然后經(jīng)過哈希函數(shù)的算法算出的值滩报,就是給定的值的在數(shù)組中的索引位置锅知。
(2)當前類中查找
- 對于
已排序好
的列表,采用二分查找
算法查找方法對應執(zhí)行函數(shù)脓钾。 - 對于
沒有排序
的列表喉镰,采用一般遍歷
查找方法對應執(zhí)行函數(shù)。
(3)父類逐級查找
截圖17.png
4.消息轉發(fā)
截圖19.png
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
RuntimeObject *obj = [[RuntimeObject alloc] init];
[obj test];
return YES;
}
#import <Foundation/Foundation.h>
@interface RuntimeObject : NSObject
- (void)test;
@end
#import "RuntimeObject.h"
@implementation RuntimeObject
+ (BOOL)resolveInstanceMethod:(SEL)sel{
//如果test方法 打印日志
if (sel == @selector(test)) {
NSLog(@"resolveInstanceMethod:");
return NO;
}else{
return [super resolveInstanceMethod:sel];
}
}
- (id)forwardingTargetForSelector:(SEL)aSelector{
NSLog(@"forwardingTargetForSelector");
return nil;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
if (aSelector == @selector(test)) {
NSLog(@"methodSignatureForSelector");
// v代表返回值是void類型 @代表第一個參數(shù)類型是id惭笑,即self
// : 代表第二個參數(shù)是SEL類型的,即@selector(test)
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}else{
return [super methodSignatureForSelector:aSelector];
}
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
NSLog(@"forwardInvocation");
}
打印結果:
截圖.png
5.Method-Swizzling
截圖20.png
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
RuntimeObject *obj = [[RuntimeObject alloc] init];
[obj test];
return YES;
}
#import <Foundation/Foundation.h>
@interface RuntimeObject : NSObject
- (void)test;
- (void)otherTest;
@end
#import "RuntimeObject.h"
#import <objc/runtime.h>
@implementation RuntimeObject
+ (void)load{
//獲取test方法
Method test = class_getInstanceMethod(self, @selector(test));
//獲取otherTest
Method otherTest = class_getInstanceMethod(self, @selector(otherTest));
//交換兩個方法的實現(xiàn)
method_exchangeImplementations(test, otherTest);
}
- (void)test{
NSLog(@"test");
}
- (void)otherTest{
//實際上調用test的具體實現(xiàn)
[self otherTest];
NSLog(@"otherTest");
}
+ (BOOL)resolveInstanceMethod:(SEL)sel{
//如果test方法 打印日志
if (sel == @selector(test)) {
NSLog(@"resolveInstanceMethod:");
return NO;
}else{
return [super resolveInstanceMethod:sel];
}
}
- (id)forwardingTargetForSelector:(SEL)aSelector{
NSLog(@"forwardingTargetForSelector");
return nil;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
if (aSelector == @selector(test)) {
NSLog(@"methodSignatureForSelector");
// v代表返回值是void類型 @代表第一個參數(shù)類型是id生真,即self
// : 代表第二個參數(shù)是SEL類型的沉噩,即@selector(test)
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}else{
return [super methodSignatureForSelector:aSelector];
}
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
NSLog(@"forwardInvocation");
}
@end
打印結果
截圖21.png
6.動態(tài)添加方法
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
RuntimeObject *obj = [[RuntimeObject alloc] init];
[obj test];
return YES;
}
#import <Foundation/Foundation.h>
@interface RuntimeObject : NSObject
- (void)test;
@end
#import "RuntimeObject.h"
#import <objc/runtime.h>
@implementation RuntimeObject
void testImp(void)
{
NSLog(@"test invoke");
}
+ (BOOL)resolveInstanceMethod:(SEL)sel{
//如果test方法 打印日志
if (sel == @selector(test)) {
NSLog(@"resolveInstanceMethod:");
class_addMethod(self, @selector(test),testImp,"v@:");
return YES;
}else{
return [super resolveInstanceMethod:sel];
}
}
打印結果
截圖19.png