Objective-C 擴展了 C 語言,並加入了面向對象特性和 Smalltalk 式的消息傳遞機制。而這個擴展的核心是一個用 C 和 編譯語言 寫的 Runtime 庫。它是 Objective-C 面向對象和動態機制的基石。
Objective-C 是一個動態語言,這意味着它不只須要一個編譯器,也須要一個運行時系統來動態得建立類和對象、進行消息傳遞和轉發。理解 Objective-C 的 Runtime 機制能夠幫咱們更好的瞭解這個語言,適當的時候還能對語言進行擴展,從系統層面解決項目中的一些設計或技術問題。瞭解 Runtime ,要先了解它的核心 - 消息傳遞 (Messaging)。
//類 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;
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;
struct objc_class結構體定義了不少變量,經過命名不難發現,html
/// Represents an instance of a class. struct objc_object { Class isa OBJC_ISA_AVAILABILITY; }; /// A pointer to an instance of a class. typedef struct objc_object *id;
類對象中的元數據存儲的都是如何建立一個實例的相關信息,那麼類對象和類方法應該從哪裏建立呢?git
就是從isa指針指向的結構體建立,類對象的isa指針指向的咱們稱之爲元類(metaclass),github
經過上圖咱們能夠看出整個體系構成了一個自閉環,struct objc_object結構體實例它的isa指針指向類對象,編程
元類(Meta Class)是一個類對象的類。緩存
struct objc_method { SEL _Nonnull method_name OBJC2_UNAVAILABLE; char * _Nullable method_types OBJC2_UNAVAILABLE; IMP _Nonnull method_imp OBJC2_UNAVAILABLE; } OBJC2_UNAVAILABLE;
Method和咱們平時理解的函數是一致的,就是表示可以獨立完成一個功能的一段代碼,好比:這段代碼,就是一個函數。數據結構
Objc.h /// An opaque type that represents a method selector.表明一個方法的不透明類型 typedef struct objc_selector *SEL;
objc_msgSend函數第二個參數類型爲SEL,它是selector在Objective-C中的表示類型(Swift中是Selector類)。selector是方法選擇器,能夠理解爲區分方法的 ID,而這個 ID 的數據結構是SEL:併發
/// A pointer to the function of a method implementation. 指向一個方法實現的指針 typedef id (*IMP)(id, SEL, ...); #endif
就是指向最終實現程序的內存地址的指針。app
name:是指 class_name 而不是 category_name。
cls:要擴展的類對象,編譯期間是不會定義的,而是在Runtime階段經過name對 應到對應的類對象。
instanceMethods:category中全部給類添加的實例方法的列表。
classMethods:category中全部添加的類方法的列表。
protocols:category實現的全部協議的列表。
instanceProperties:表示Category裏全部的properties,這就是咱們能夠經過objc_setAssociatedObject和objc_getAssociatedObject增長實例變量的緣由,不過這個和通常的實例變量是不同的。
從上面的category_t的結構體中能夠看出,分類中能夠添加實例方法,類方法,甚至能夠實現協議,添加屬性,不能夠添加成員變量。框架
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. //執行foo函數 [self performSelector:@selector(foo:)]; } + (BOOL)resolveInstanceMethod:(SEL)sel { if (sel == @selector(foo:)) {//若是是執行foo函數,就動態解析,指定新的IMP class_addMethod([self class], sel, (IMP)fooMethod, "v@:"); return YES; } return [super resolveInstanceMethod:sel]; } void fooMethod(id obj, SEL _cmd) { NSLog(@"Doing foo");//新的foo函數 }
打印結果:2018-04-01 12:23:35.952670+0800 ocram[87546:23235469] Doing foo
#import "ViewController.h" #import "objc/runtime.h" @interface Person: NSObject @end @implementation Person - (void)foo { NSLog(@"Doing foo");//Person的foo函數 } @end @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. //執行foo函數 [self performSelector:@selector(foo)]; } + (BOOL)resolveInstanceMethod:(SEL)sel { return YES;//返回YES,進入下一步轉發 } - (id)forwardingTargetForSelector:(SEL)aSelector { if (aSelector == @selector(foo)) { return [Person new];//返回Person對象,讓Person對象接收這個消息 } return [super forwardingTargetForSelector:aSelector]; } @end
打印結果:2018-04-01 12:45:04.757929+0800 ocram[88023:23260346] Doing foo
#import "ViewController.h" #import "objc/runtime.h" @interface Person: NSObject @end @implementation Person - (void)foo { NSLog(@"Doing foo");//Person的foo函數 } @end @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. //執行foo函數 [self performSelector:@selector(foo)]; } + (BOOL)resolveInstanceMethod:(SEL)sel { return YES;//返回YES,進入下一步轉發 } - (id)forwardingTargetForSelector:(SEL)aSelector { return nil;//返回nil,進入下一步轉發 } - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { if ([NSStringFromSelector(aSelector) isEqualToString:@"foo"]) { return [NSMethodSignature signatureWithObjCTypes:"v@:"];//簽名,進入forwardInvocation } return [super methodSignatureForSelector:aSelector]; } - (void)forwardInvocation:(NSInvocation *)anInvocation { SEL sel = anInvocation.selector; Person *p = [Person new]; if([p respondsToSelector:sel]) { [anInvocation invokeWithTarget:p]; } else { [self doesNotRecognizeSelector:sel]; } } @end
打印結果:2018-04-01 13:00:45.423385+0800 ocram[88353:23279961] Doing foo