在OC中,消息与方法的真正实现是在执行阶段绑定的。
编译器会将消息转发成对objc_msgSend方法的调用。
objc_msgSend方法含有两个必要的参数:receiver、selector,如:
[receiver message] 将被转换为objc_msgSend(receiver,selector);
objc_msgSend方法也能收到message的参数,如
objc_msgSend(receiver, selector, arg1, arg2, …);
objc_msgSend方法会做按照顺序进行以下操作,以完成动态绑定:
消息传递的关键是,编译器构建每个类和对象时所采用的数据结构。每个类都包含以下两个必要的元素:
类的底层构造如下:
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY; //isa指针
#if !__OBJC2__ Class
super_class OBJC2_UNAVAILABLE; // 父类
const char *name OBJC2_UNAVAILABLE; // 类名
long version OBJC2_UNAVAILABLE; // 类的版本信息,默认为0
long info OBJC2_UNAVAILABLE; // 类信息
long instance_size OBJC2_UNAVAILABLE; // 类占据的内存大小
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 成员变量链表
struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法链表
struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法缓存列表
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 协议链表
#endif
} OBJC2_UNAVAILABLE;
objc在向一个对象发送消息时,runtime库会根据对象的isa指针找到该对象实际所属的类,然后在该类中的方法列表以及其父类方法列表中寻找方法运行。如果在层层的寻找中,均未找到方法的实现,就是会抛出unrecognized selector sent to XXX
的异常,导致程序崩溃。
但是,在crash之前,OC的运行时系统会先经过以下两个步骤:
首先,如果调用的方法是实例方法,OC的运行时会调用+ (BOOL)resolveInstanceMethod:(SEL)sel
,如果是类方法,则会调用+ (BOOL)resolveClassMethod:(SEL)sel
让我们可以在程序运行时动态的为一个selector提供实现,如果我们添加了函数的实现,并返回YES,运行时系统会重启一次消息的发送过程,调用动态添加的方法。例如,下面的例子:
+ (BOOL)resolveInstanceMethod:(SEL)sel {
NSLog(@"未实现实例方法: %@",NSStringFromSelector(sel));
if (sel == @selector(testMessage)) {
class_addMethod([self class], sel, (IMP)dynamicMethodIMP, "V@:");
}
return [super resolveInstanceMethod:sel];
}
void dynamicMethodIMP(id target, SEL sel) {
NSLog(@"动态添加实例方法 %s", __PRETTY_FUNCTION__);
}
class_addMethod 方法动态的添加新的方法与对应的实现,如果调用了[test testMessage],将会转到动态添加的dynamicMethodIMP 方法中。Objective-C的方法本质上是一个至少包含两个参数(id self, SEL _cmd)的C函数
,这样,当重启消息发送时,就能在类中找到@selector(testMessage)了。而如果方法返回NO时,将会进入下一步:消息转发(Message Forwarding)
消息转发分为两步:
- (id)forwardingTargetForSelector:(SEL)aSelector方法
,如果这个方法中返回的不是nil或者self,运行时系统将把消息发送给返回的那个对象- (id)forwardingTargetForSelector:(SEL)aSelector
返回的是nil或者self,运行时系统首先会调用- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
方法来获得方法签名,方法签名记录了方法的参数和返回值的信息,如果-methodSignatureForSelector
返回的是nil, 运行时系统会抛出unrecognized selector exception
,程序到这里就结束了#import
@interface MutipleDelegate : NSObject
/** 不增加这个对象的引用计数 */
@property (nonatomic, strong) NSPointerArray *weakRefTagets;
/** 添加一个代理对象 */
- (void)addDelegate:(id)delegate;
@end
#import "MutipleDelegate.h"
@implementation MutipleDelegate
- (void)addDelegate:(id)delegate {
[self.weakRefTagets addPointer:(__bridge void * _Nullable)(delegate)];
}
- (NSPointerArray *)weakRefTagets {
if (_weakRefTagets == nil) {
_weakRefTagets = [NSPointerArray weakObjectsPointerArray];
}
return _weakRefTagets;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
NSMethodSignature *sign = [super methodSignatureForSelector:aSelector];
if (sign == nil) {
for (id target in self.weakRefTagets) {
if ((sign = [target methodSignatureForSelector:aSelector])) {
break ;
}
}
}
return sign;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
for (id target in self.weakRefTagets) {
if ([target respondsToSelector:anInvocation.selector]) {
[anInvocation invokeWithTarget:target];
}
}
}
- (BOOL)respondsToSelector:(SEL)aSelector {
if ([super respondsToSelector:aSelector]) {
return YES;
}
for (id target in self.weakRefTagets) {
if ([target respondsToSelector:aSelector]) {
return YES;
}
}
return NO;
}
@end