iOS开发基础之消息传递

在项目编码中最为常见的就是[object message];这种形式的消息发送,对于其他面向对象语言来说就是实例对象调用类中实现的实例方法;[object message]这种形式到底做了什么呢?

objc_object, objc_class 以及 objc_method

在Objective-C中类、对象、方法都是C语言中结构体类型;具体数据类型可以参照objc/objc.h文件

  // 类
  struct objc_class {
                         Class isa;//指针,顾名思义,表示是一个什么,
                         //实例的isa指向类对象,类对象的isa指向元类
                         #if !__OBJC2__
                         Class super_class;  //指向父类
                         const char *name;  //类名
                         long version;
                         long info;
                         long instance_size
                         struct objc_ivar_list *ivars //成员变量列表
                         struct objc_method_list **methodLists; //方法列表
                         struct objc_cache *cache;//缓存一种优化,调用过的方法存入缓存列表,下次调用先找缓存
                         struct objc_protocol_list *protocols //协议列表
                         #endif
             } OBJC2_UNAVAILABLE;
             
  //对象 
             struct objc_object {
                     Class isa  OBJC_ISA_AVAILABILITY;
             };
 // 方法
             struct objc_method {
                     SEL method_name                 OBJC2_UNAVAILABLE;  // 方法名
                     char *method_types                  OBJC2_UNAVAILABLE;
                     IMP method_imp                      OBJC2_UNAVAILABLE;  // 方法实现
             }

消息的传递

People类中声明并实现walk方法则消息会正常被传递
    #import <Foundation/Foundation.h>
    @interface HZPeople : NSObject
    -(void)walk;
    @end
    
    #import "HZPeople.h"
    #import <objc/objc-runtime.h>
    @implementation HZPeople
    -(void)walk{
        NSLog(@"people walk!!");
    }

控制台能正常打印 people walk!!

如果只声明并不是实现walk方法则会调用+(BOOL)resolveInstanceMethod:(SEL)sel;允许在此进行对类增加方法
    #import <Foundation/Foundation.h>
    @interface HZPeople : NSObject
    -(void)walk;
    @end
    
    #import "HZPeople.h"
    #import <objc/objc-runtime.h>
    @implementation HZPeople
    
    void anotherPeopleWalk(id obj ,SEL _cmd){
NSLog(@"anotherPeopleWalk!");
}
    +(BOOL)resolveInstanceMethod:(SEL)sel{
NSLog(@"resolveInstanceMethod!");
if (sel == @selector(walk)) {
  // 通过imp_implementationWithBlock执行新增方法事项
    IMP fooIMP = imp_implementationWithBlock(^(id _self) {
        NSLog(@"Doing foo");
    });
    // 给类动态添加执行方法
    class_addMethod([self class], sel, fooIMP, "v@:");
  //  class_addMethod([self class], sel, (IMP)anotherPeopleWalk, "v@:");
    return YES;
}
return [super resolveInstanceMethod:sel];
}

控制台会先打印resolveInstanceMethod然后打印Doing foo

+(BOOL)resolveInstanceMethod:(SEL)sel中没有实现方法的新增则会调用-(id)forwardingTargetForSelector:(SEL)aSelector允许对消息转发给其他对象
   #import <Foundation/Foundation.h>
    #import "HZMan.h"
    @interface HZPeople : NSObject
    @property(nonatomic,strong)HZMan* man;
    -(void)walk;
    @end
    
    #import "HZPeople.h"
    #import <objc/objc-runtime.h>
    @implementation HZPeople
    
    -(id)forwardingTargetForSelector:(SEL)aSelector{
if (aSelector == @selector(walk)) {
    // 将消息转发给HZMan中的walk方法
    return self.man;
}
return [super forwardingTargetForSelector:aSelector];
}
-(id)forwardingTargetForSelector:(SEL)aSelector如果没有实现还有最后的机会进行一次消息转发;这个需要重写- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector为执行方法进行签名,最后在实现-(void)forwardInvocation:(NSInvocation *)anInvocation完成一次消息的完整转发
 #import <Foundation/Foundation.h>
    #import "HZMan.h"
    @interface HZPeople : NSObject
    @property(nonatomic,strong)HZMan* man;
    -(void)walk;
    @end
    
    #import "HZPeople.h"
    #import <objc/objc-runtime.h>
    @implementation HZPeople
    
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
NSMethodSignature* signature = [super methodSignatureForSelector:aSelector];
if(!signature){
    signature = [_man methodSignatureForSelector:aSelector];
}
return signature;
}
-(void)forwardInvocation:(NSInvocation *)anInvocation{
    SEL sel = anInvocation.selector;
    if ([self .man respondsToSelector:sel]) {
        [anInvocation invokeWithTarget:self.man];
    }else{
        [self doesNotRecognizeSelector:sel];
    }
}
如果最终也没有对消息进行处理就只能执行doesNotRecognizeSelector:sel抛出异常了

几个概念

SEL
  • SEL:选择器,是表示一个方法的selector的指针
  • typedef struct objc_selector *SEL;
  • Objective-C在编译时,会依据每一个方法的名字、参数序列,生成一个唯一的整型标识(Int类型的地址),这个标识就是SEL
  • 本质上,SEL只是一个指向方法的指针(准确的说,只是一个根据方法名hash化了的KEY值,能唯一代表一个方法),它的存在只是为了加快方法的查询速度。
IMP
  • IMP:实际上是一个函数指针,指向方法实现的首地址
  • id (*IMP)(id, SEL, ...)
  • 参数1:实例方法或者是类方法 分别代表类实例的内存地址或是指向原类的指针
Method

Method :表示类定义的方法

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 5,806评论 0 9
  • 本文转载自:http://yulingtianxia.com/blog/2014/11/05/objective-...
    ant_flex阅读 4,162评论 0 1
  • 我们常常会听说 Objective-C 是一门动态语言,那么这个「动态」表现在哪呢?我想最主要的表现就是 Obje...
    Ethan_Struggle阅读 6,572评论 0 7
  • 简介 Runtime 又叫运行时,是一套底层的 C 语言 API,其为 iOS 内部的核心之一,我们平时编写的 O...
    专业男神经阅读 4,377评论 0 2
  • 参考链接: http://www.cnblogs.com/ioshe/p/5489086.html 简介 Runt...
    乐乐的简书阅读 6,445评论 0 9