標籤:style blog http io color os ar for sp
序言
如果我們在 Objective C 中向一個對象發送它無法處理的訊息,會出現什麼情況呢?根據前文《深入淺出Cocoa之訊息》的介紹,我們知道發送訊息是通過 objc_send(id, SEL, ...) 來實現的,它會首先在對象的類對象的 cache,method list 以及父類對象的 cache, method list 中依次尋找 SEL 對應的 IMP;如果沒有找到且實現了動態方法決議機制就會進行決議,如果沒有實現動態方法決議機制或決議失敗且實現了訊息轉寄機制就會進入訊息轉寄流程,否則程式 crash。也就是說如果同時提供了動態方法決議和訊息轉寄,那麼動態方法決議先於訊息轉寄,只有當動態方法決議依然無法正確決議 selector 的實現,才會嘗試進行訊息轉寄。在前文中,我並沒有詳細講解動態方法決議,因此本文將詳細介紹之。
1 #import <Foundation/Foundation.h>2 3 @interface PrettyGirl : NSObject4 5 -(void)loveMe;6 7 @end
1 #import "PrettyGirl.h" 2 3 @implementation PrettyGirl 4 5 -(void)loveMe 6 { 7 NSLog(@"Pretty Girl Love Me!"); 8 } 9 10 @end
1 #import <Foundation/Foundation.h> 2 #import "PrettyGirl.h" 3 4 int main (int argc, const char * argv[]) 5 { 6 7 @autoreleasepool { 8 9 PrettyGirl *xiaoQian=[[PrettyGirl alloc]init];10 [xiaoQian loveMe];11 [xiaoQian Movie];12 [xiaoQian release];13 14 }15 return 0;16 }
運行結果
1 2014-10-27 21:03:25.899 DeeoIntoMethod[4010:303] Pretty Girl Love Me! 2 2014-10-27 21:03:25.901 DeeoIntoMethod[4010:303] -[PrettyGirl Movie]: unrecognized selector sent to instance 0x100200980 3 2014-10-27 21:03:25.902 DeeoIntoMethod[4010:303] *** Terminating app due to uncaught exception ‘NSInvalidArgumentException‘, reason: ‘-[PrettyGirl Movie]: unrecognized selector sent to instance 0x100200980‘ 4 *** First throw call stack: 5 ( 6 0 CoreFoundation 0x00007fff8a13925c __exceptionPreprocess + 172 7 1 libobjc.A.dylib 0x00007fff8c866e75 objc_exception_throw + 43 8 2 CoreFoundation 0x00007fff8a13c12d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205 9 3 CoreFoundation 0x00007fff8a097272 ___forwarding___ + 101010 4 CoreFoundation 0x00007fff8a096df8 _CF_forwarding_prep_0 + 12011 5 DeeoIntoMethod 0x0000000100001acd main + 12512 6 DeeoIntoMethod 0x0000000100001a44 start + 5213 7 ??? 0x0000000000000001 0x0 + 114 )15 libc++abi.dylib: terminating with uncaught exception of type NSException
[PrettyGirl Movie]: unrecognized selector sent to instance 0x100200980這句表示在方法列表中尋找不到方法,因此程式crash
好了,這裡我們用動態決議來解決這個問題
1 #import <Foundation/Foundation.h> 2 #import "PrettyGirl.h" 3 4 int main (int argc, const char * argv[]) 5 { 6 7 @autoreleasepool { 8 9 PrettyGirl *xiaoQian=[[PrettyGirl alloc]init];10 [xiaoQian loveMe];11 [xiaoQian Movie];12 [xiaoQian release];13 }14 return 0;15 }
1 #import <Foundation/Foundation.h>2 3 @interface PrettyGirl : NSObject4 5 -(void)loveMe;6 7 @end
1 #import "PrettyGirl.h" 2 #include <objc/runtime.h> 3 4 void putonCoat(NSString *str) 5 { 6 NSLog(@" >> putonCoat."); 7 } 8 9 10 @implementation PrettyGirl11 12 -(void)loveMe13 {14 NSLog(@"Pretty Girl Love Me!");15 }16 17 +(BOOL)resolveClassMethod:(SEL)sel18 {19 if(sel==@selector(Movie))20 {21 class_addMethod([self class],sel,(IMP)putonCoat,"[email protected]:@");22 }23 return [super resolveClassMethod:sel];24 }25 26 +(BOOL)resolveInstanceMethod:(SEL)sel27 {28 if(sel==@selector(Movie))29 {30 class_addMethod([self class],sel,(IMP)putonCoat,"[email protected]:@");31 }32 return [super resolveClassMethod:sel];33 }34 35 @end
class_addMethod方法第一個參數是要執行的類[self class],第二個參數是方法名sel,第三個參數是要代替的方法指標,最後一個方法是參數
參數解釋:
i:返回int類型,v表示無傳回值
@:參數id(self)
:SEL(_cmd)
@:id(str)
ios底層開發訊息機制(三)動態方法決議