美文网首页M_iOSiOS小筑
iOS开发基础之消息传递

iOS开发基础之消息传递

作者: 华子小筑 | 来源:发表于2015-11-19 12:01 被阅读121次

在项目编码中最为常见的就是[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 :表示类定义的方法

相关文章

  • iOS开发基础之消息传递

    在项目编码中最为常见的就是[object message];这种形式的消息发送,对于其他面向对象语言来说就是实例对...

  • iOS开发需要掌握的技能篇

    基础知识储备1. iOS的消息传递方式-1.通知2.iOS的消息传递方式-2.代理3.iOS的消息传递方式-3.B...

  • Mach消息发送机制

    目录 Mach基础 Mach作用 Mach消息简单消息复杂消息端口 消息传递实现 Mach基础 Mach是iOS的...

  • iOS 响应链

    iOS开发 - 事件传递响应链iOS 响应者链,事件的传递事件传递之响应链Cocoa Touch事件处理流程--响...

  • iOS基础(八) - runtime之消息传递

    前言:本来是想整理一下runtime相关的知识的,谁知道,越陷越深,一个知识点连着一个知识点,我怕以后忘记,所以,...

  • runtime总结

    iOS开发之Runtime 苹果官方文档 博客-iOS基础 iOS开发系列--并行开发其实很容易 优质博客列表 优...

  • iOS模式之二:代理模式

    iOS中消息传递方式 在iOS中有很多种消息传递方式,这里先简单介绍一下各种消息传递方式。 通知:在iOS中由通知...

  • iOS开发---图解代理

    什么是代理? 代理(Delegate)是iOS开发中的一种重要的消息传递方式,是iOS开发中普遍使用的通用设计模式...

  • iOS知识点(11)UITableView

    最基础的UITableView知识讲解iOS开发之UITableView全面解析 iOS UITableView的...

  • iOS消息传递之KVO

      KVO简介:键值观察,是基于键值编码(KVC)的一种观察模式。 是iOS中常用的一种消息传递机制。  对接模...

网友评论

    本文标题:iOS开发基础之消息传递

    本文链接:https://www.haomeiwen.com/subject/icklhttx.html