一 概述:
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类型,编译器会认为这个属性相关的方法会动态提供,也就是说编译器不会默认生成属性的set
和get
方法了,而需要我们动态提供,可以通过重载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/
网友评论