zoukankan      html  css  js  c++  java
  • 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 : NSObject
    4 
    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___ + 1010
    10     4   CoreFoundation                      0x00007fff8a096df8 _CF_forwarding_prep_0 + 120
    11     5   DeeoIntoMethod                      0x0000000100001acd main + 125
    12     6   DeeoIntoMethod                      0x0000000100001a44 start + 52
    13     7   ???                                 0x0000000000000001 0x0 + 1
    14 )
    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 : NSObject
    4 
    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 PrettyGirl
    11 
    12 -(void)loveMe
    13 {
    14     NSLog(@"Pretty Girl Love Me!");
    15 }
    16 
    17 +(BOOL)resolveClassMethod:(SEL)sel
    18 {
    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)sel
    27 {
    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)
  • 相关阅读:
    cmd 窗口中运行 Java 程序
    局部变量保证线程安全
    AQS源码详细解读
    理解 Java 内存模型的因果性约束
    高性能Java序列化框架Fse发布
    心跳与超时:高并发高性能的时间轮超时器
    支持内部晋升的无锁并发优先级线程池
    最终一致性:BASE论文笔记
    Activiti架构分析及源码详解
    理解OAuth2
  • 原文地址:https://www.cnblogs.com/guchengfengyun/p/4055523.html
Copyright © 2011-2022 走看看