objective-c提供了一种名为动态方法决议的手段,使得我们可以在运行时动态地为一个selector提供实现。我们只要实现+resolveInstanceMethod:和+resolveClassMethod:方法,并在其中为指定的selector提供实现即可(通过调用运行时函数class_addMethod来添加)。这连个方法都是NSObject中的类方法,其原型为:
+ (BOOL)resolveClassMethod:(SEL)name;
+ (BOOL)resolveInstanceMethod:(SEL)name;
参数name是需要被冬天决议的selector;返回值文档中说是表示动态决议成功与否。但在上面的例子中(不涉及消息转发的情况下),如果在该函数内为指定的selector提供实现,无论返回YES还是NO,编译运行都是正确的;但如果在该函数内并不真正为selector提供实现,无论返回YES还是NO,运行都会crash,道理很简单,selector并没有对应的而实现,而又没有实现消息转发。resolveInstanceMethod是为对象方法进行决议,而resolveClassMethod是为类方法进行决议。
//
// Foo.m
// DeepIntoMethod
//
// Created by 飘飘白云 on 12-11-13.
// Copyright (c) 2012年 kesalin@gmail.com All rights reserved.
//
#import "Foo.h"
#include <objc/runtime.h>
void dynamicMethodIMP(id self, SEL _cmd) {
NSLog(@" >> dynamicMethodIMP");
}
@implementation Foo
-(void)Bar
{
NSLog(@" >> Bar() in Foo");
}
+ (BOOL)resolveInstanceMethod:(SEL)name
{
NSLog(@" >> Instance resolving %@", NSStringFromSelector(name));
if (name == @selector(MissMethod)) {
class_addMethod([self class], name, (IMP)dynamicMethodIMP, "v@:");
return YES;
}
return [super resolveInstanceMethod:name];
}
+ (BOOL)resolveClassMethod:(SEL)name
{
NSLog(@" >> Class resolving %@", NSStringFromSelector(name));
return [super resolveClassMethod:name];
}
@end
理解这段代码:
1、首先判断是否实现了resolveInstanceMethod,如果没有实现,返回NULL,进入下一步处理
2、如果实现了,调用resolveInstanceMethod,获取返回值
3、如果返回值为YES,表示resolveInstanceMethod声称它已经提供了selector的实现,因此再次查找method list,如果依然找到相应的IMP,则返回该实现,否则提示警告信息,返回NULL,进入下一步处理
4、如果返回值为NO,返回NULL,进入下一步处理。
只有在resolveInstanceMethod的实现中没有真正为selector提供实现,并返回NO的情况下才会进入消息转发流程;否则绝不会进入消息转发流程,程序要么调用正确的动态方法,要么crash。