Objective-C消息发送

2018-03-26  本文已影响59人  Hunter琼

一 概述:
Objective-C(简称OC)的Cocoa层的API中有大量的[receiver message]消息发送机制,初学时我们往往把理解为一个object调用了一个method,而往往忽视了"消息机制"这句话的深刻含义,[receiver message]独特机制区别于其他主流语言,这也是很多软件开发者转型iOS 选择Swift原因了.
二 原理:
消息发送机制是Runtime通过selector快速查找IMP的过程,有了IMP这个函数指针,就可以执行对应的方法实现.
[receiver message]会被编译器转换成为:

// arg1 ,arg2... 表示消息含有的参数
objc_msgSend(receiver, selector, arg1, arg2, ...)

如果消息的接受者能够找到对应的selector,相当于执行了这个对象方法,否则消息要么被转发,要么临时向接受者动态添加这个 selector 对应的实现内容,要么就干脆崩溃

IMP:定义为 typedef void (*IMP)(void /* id,SEL,... */);本质是个函数指针,由编译器生成,当发送一条消息之后,最终它会执行方法,就是由该函数指针定的,而IMP这个函数指针就是指向了这个方法的实现.
三 super
super是OC的保留字,不是隐式参数,它只是个''编译器指示器',主要是针对父类
id objc_msgSendSuper(struct objc_super *super,SEL op,...)
当消息传递给父类的时候,调用objc_msgSendSuper,objc_super 这个结构体会存放当前函数里的self(隐式参数)的super_class,即[self superclass];msgSendSuper从当前对象的父类方法开始,沿着父类继承链查找.最终执行到[super respondsToSelector:@selector(superHasNotThisSelector) ]; 而respondsToSelector这个方法是NSObject方法,而NSObjcet类位于所有类继承的顶端,执行这个方法会找到对应的实现函数!
四 self
self是OC的隐式参数,之所以叫隐式参数是因为源代码方法定义中并没有声明这个参数,但我们可以引用它;self本身也是个指针,在每个方法中都有一个self指针,在函数中无法使用,可以使用self -> 成员变量
五 动态方法
前面提到某些情况下消息的接受者无法找到对应的selector时,会临时向接受者动态添加这个selector对应的实现内容.
给某个属性声明@dynamic类型,编译器会认为这个属性相关的方法会动态提供,也就是说编译器不会默认生成属性的setget方法了,而需要我们动态提供,可以通过重载resolveInstanceMethod:resolveClassMethod添加动态方法.
代码示例如下:

#import <Foundation/Foundation.h>

@interface AutoMehtodModel : NSObject
@property(nonatomic,copy)NSString *addAutoMethod;

@end
#import "AutoMehtodModel.h"
#import <objc/runtime.h>
@implementation AutoMehtodModel
@dynamic addAutoMethod;
/**
  为addAutoMethod动态添加set和get方法
 **/
 +(BOOL)resolveInstanceMethod:(SEL)sel
{
    NSString *addSelectorStr = NSStringFromSelector(sel);
    //v@:@是一种符合 涉及到https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
    if ([addSelectorStr isEqualToString:@"setAddAutoMethod:"]) {
        class_addMethod(self, sel, (IMP)autoSetter, "v@:@");
    }else if ([addSelectorStr isEqualToString:@"addAutoMethod"]){
        class_addMethod(self, sel, (IMP)autoGet, "@@:");
    }
    return [super resolveInstanceMethod:sel];
}

void autoSetter(id self,SEL _cmd, id value){
    NSLog(@"set方法 === %@",value);
    
}

id autoGet(id self,SEL _cmd){
    return @"get方法";
}
 AutoMehtodModel *model = [[AutoMehtodModel alloc]init];
    model.addAutoMethod   = @"动态方法";
    NSLog(@"%@",model.addAutoMethod);

运行结果:

2018-03-27 10:53:07.875514+0800 OC_Categroy[962:61285] set方法 === 动态方法
2018-03-27 10:53:23.157687+0800 OC_Categroy[962:61285] get方法

参考文献:http://yulingtianxia.com/blog/2014/11/05/objective-c-runtime/

上一篇 下一篇

猜你喜欢

热点阅读