参考:Objective-C Runtime Programming Guide
demo 链接
向一个oc对象发送一个不存在的消息,会抛出 unrecognized selector sent to instance xxx 的异常,导致程序终止。
在抛出异常之前,用户有机会通过动态方法解析或者消息转发来阻止异常的发生

动态方法解析
/*
动态解析
1. 可以解析实例方法
2. 可以解析类方法
*/
Resolver *resolver = [[Resolver alloc] init];
[resolver doSomething];
[Resolver doSomething];
Resolver
@interface Resolver : NSObject
- (void)doSomething;
+ (void)doSomething;
@end
@implementation Resolver
void instanceMethodIMP(id self, SEL _cmd) {
NSLog(@"%s",__FUNCTION__);
}
void classMethodIMP(id self, SEL _cmd) {
NSLog(@"%s",__FUNCTION__);
}
+ (BOOL)resolveClassMethod:(SEL)sel {
if (sel == @selector(doSomething)) {
Class meta = object_getClass([self class]);
class_addMethod(meta, @selector(doSomething), (IMP)classMethodIMP, "v@:");
return YES;
}
return [super resolveClassMethod:sel];
}
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if (sel == @selector(doSomething)) {
class_addMethod([self class], @selector(doSomething), (IMP)instanceMethodIMP, "v@:");
return YES;
}
return [super resolveClassMethod:sel];
}
@end
转发给其他对象
/*
快速转发,将消息转发给别的可以响应的对象
*/
Receiver *receiver = [[Receiver alloc] init];
[receiver doSomething];
Receiver
@interface Receiver : NSObject
- (void)doSomething;
@end
@interface Receiver ()
@property (nonatomic, strong) Handler *handler;
@end
@implementation Receiver
- (instancetype)init
{
self = [super init];
if (self) {
_handler = [[Handler alloc] init];
}
return self;
}
- (id)forwardingTargetForSelector:(SEL)aSelector {
if (aSelector == @selector(doSomething)) {
if ([_handler respondsToSelector:aSelector]) {
return _handler;
}
}
return [super forwardingTargetForSelector:aSelector];
}
@end
Handler
@interface Handler : NSObject
- (void)doSomething;
@end
@implementation Handler
- (void)doSomething {
NSLog(@"%s",__FUNCTION__);
}
@end
NSInvocation
转发
/*
对消息重新签名,通过invocation来转发
1. 可以修改参数,返回值,接受对象
2. 将消息转发给多个对象
3. 不处理的话,消息就被吞掉了
*/
AReceiver *aReceiver = [[AReceiver alloc] init];
[aReceiver doSomething];
BOOL ret = [aReceiver doSomethingWithParam1:@"param1" param2:"param2"];
NSLog(@"ret = %d",ret);
AReceiver
@interface AReceiver : NSObject
- (void)doSomething;
- (BOOL)doSomethingWithParam1:(NSString *)param1 param2:(char *)param2;
@end
@interface AHandler : NSObject
@end
@implementation AHandler
- (void)doSomething {
NSLog(@"%s",__FUNCTION__);
}
- (BOOL)doSomethingWithParam1:(NSString *)param1 param2:(char *)param2 {
NSLog(@"%s, parma1 = %@, param2 = %s",__FUNCTION__, param1, param2);
return YES;
}
- (void)doWithParam1:(NSString *)param1 param2:(char *)param2 {
NSLog(@"%s, parma1 = %@, param2 = %s",__FUNCTION__, param1, param2);
}
@end
@implementation AReceiver
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if (aSelector == @selector(doSomething)) {
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
if (aSelector == @selector(doSomethingWithParam1:param2:)) {
return [NSMethodSignature signatureWithObjCTypes:"c@:@*"];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
//将消息转发给其他对象
if (anInvocation.selector == @selector(doSomething)) {
[anInvocation invokeWithTarget:[AHandler new]];
}
if (anInvocation.selector == @selector(doSomethingWithParam1:param2:)) {
//篡改消息的参数
NSString *param1 = @"message1 hacked";
char *param2 = "message2 hacked";
[anInvocation setArgument:¶m1 atIndex:2];
[anInvocation setArgument:¶m2 atIndex:3];
//篡改消息的方法选择器
anInvocation.selector = @selector(doWithParam1:param2:);
//修改消息接收对象
[anInvocation invokeWithTarget:[AHandler new]];
//篡改消息的返回值
BOOL ret = YES;
[anInvocation setReturnValue:&ret];
}
}
@end
网友评论