参考文章:
http://www.jianshu.com/p/1bde36ad9938
http://tech.glowing.com/cn/objective-c-runtime/
Objective-C Runtime 运行时之三:方法与消息
Objective-C 扩展了 C 语言,并加入了面向对象特性和 Smalltalk 式的消息传递机制。而这个扩展的核心是一个用 C 和 编译语言 写的 Runtime 库。它是 Objective-C 面向对象和动态机制的基石。
Objective-C 是一个动态语言,这意味着它不仅需要一个编译器,也需要一个运行时系统来动态得创建类和对象、进行消息传递和转发。理解 Objective-C 的 Runtime 机制可以帮我们更好的了解这个语言,适当的时候还能对语言进行扩展,从系统层面解决项目中的一些设计或技术问题。了解 Runtime ,要先了解它的核心 - 消息传递 (Messaging)。
OC中调用方法就是向对象发送消息。
比如 :
[person run];
这实际上这是在给person这个对象发送run这个消息。
那么问题来了,当run这个方法只有定义没有实现会怎么样呢?
就是经典的报错
ok,前提已经说完了,我们就从找这个错误原因讲起。
首先,该方法在调用时,系统会查看这个对象能否接收这个消息(查看这个类有没有这个方法,或者有没有实现这个方法。),如果不能并且只在不能的情况下,就会调用下面这几个方法,给你“补救”的机会,你可以先理解为几套防止程序crash的备选方案,我们就是利用这几个方案进行消息转发,注意一点,前一套方案实现后一套方法就不会执行。如果这几套方案你都没有做处理,那么程序就会报错crash。
打个比方:比赛足球时,脚下有球的那名球员,如果他的位置不利于射门或者他的球即将被对方球员抢断,这时最好是把球传出去,这里的球就相当于消息。
-(id)initWithName:(id)obj1 obj2:(id)obj2
{
_realObj1 = obj1;
_realObj2 = obj2;
return self;
}
-(NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
NSMethodSignature *s1;
s1 = [_realObj1 methodSignatureForSelector:sel];
if (s1) { return s1;}
s1 = [_realObj2 methodSignatureForSelector:sel];
return s1;
}
-(void)forwardInvocation:(NSInvocation *)invocation
{
id target = [_realObj1 methodSignatureForSelector:[invocation selector]]?_realObj1:_realObj2;
[invocation invokeWithTarget:target];
}
-(BOOL)respondsToSelector:(SEL)aSelector
{
if ([_realObj1 respondsToSelector:aSelector]) return YES;
else if([_realObj2 respondsToSelector:aSelector])return YES;
return NO;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableString *string = [[NSMutableString alloc]init];
NSMutableArray *array = [[NSMutableArray alloc]initWithCapacity:10];
id proxy = [[myProxy alloc]initWithName:string obj2:array];
[proxy appendString:@"this "];
[proxy addObject:string];
[proxy appendString:@"is "];
[proxy appendString:@"a "];
[proxy appendString:@"proxy"];
NSLog(@"this should be 1 it is %li",[proxy count]);
if ([[proxy objectAtIndex:0] isEqualToString:@"this is a proxy"]) {
NSLog(@"appendString Successful");
}
}
系统就会调用两个方法methodSignatureForSelector和forwardInvocation
methodSignatureForSelector用来生成方法签名,这个签名就是给forwardInvocation中的参数NSInvocation调用的。
开头我们要找的错误unrecognized selector sent to instance原因,原来就是因为methodSignatureForSelector这个方法中,由于没有找到run对应的实现方法,所以返回了一个空的方法签名,最终导致程序报错崩溃。
所以我们需要做的是自己新建方法签名,再在forwardInvocation中用你要转发的那个对象调用这个对应的签名,这样也实现了消息转发。
-(void)forwardInvocation:(NSInvocation *)invocation
{
id target = [_realObj1 methodSignatureForSelector:[invocation selector]]?_realObj1:_realObj2;
[invocation invokeWithTarget:target];
}
-(BOOL)respondsToSelector:(SEL)aSelector
{
if ([_realObj1 respondsToSelector:aSelector]) return YES;
else if([_realObj2 respondsToSelector:aSelector])return YES;
return NO;
}
程序的结果为string 会拼接字符串 this is a proxy
array会增加一个object,也就是 [proxy count]==1
且[proxy objectAtIndex:0] 就是 会转发到 [array objectAtIndex:0] 也就是@"this is a proxy",所以会成功输出
NSLog(@"appendString Successful");
欢迎转载:请尊重原创,注明出处 http://blog.csdn.net/lcg910978041/article/details/51902470
github地址:点击打开链接