首页 > 代码库 > ios底层开发消息机制(三)动态方法决议

ios底层开发消息机制(三)动态方法决议

序言

如果我们在 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,"i@:@");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,"i@:@");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底层开发消息机制(三)动态方法决议