Objective-C Runtime Programming Guide 笔记03 Dynamic Method Resolution
1.implement a method dynamically
@dynamic propertyName
表明会动态的提供与该属性联系的方法.
可以分别通过实现resolveInstanceMethod:和resolveClassMethod:方法来动态的实现指定选择器的实例方法或类方法.
一个Objective-C方法简单来说就是一个至少有两个参数(self 和 _cmd)的C函数.可以使用class_addMethod函数将一个函数添加为一个类方法.
void dynamicMethodIMP(id self,SEL _cmd){
//implementation...
}
使用resloveInstanceMethod:动态的将以上方法增加为一个类的方法.
@implementation MyClass
+(BOOL)resolveInstanceMethod:(SEL)aSEL{
if(aSEL == @selector(resolveThisMethodDynamically)){
class_addMethod([self class],aSEL,(IMP) dynamicMethodIMP,"v@:");
return YES;
}
return [super resolveInstanceMethod:aSEL];
}
@end
Forwarding methods 和 dynamic method 是 orthogonal的.
一个类在forwarding 机制生效前可以解析动态方法.如果调用了respondsToSelector:或instanceRespondToSelector:,动态方法解析器首先会提供给选择器一个IMP.如果你实现了resolveInstanceMethod:但是需要一个指定的选择器通过forwarding 机制更精准的传递,则需要为这个选择器 return NO.
尽管Mach-O(objc_loadModlules)中提供了动态载入Objective-C的函数,但是Cocoa’s 的NSBundle提供了更为方便的动态加载方法(dynamic loading).
2. Message Forwarding
向不处理消息的对象发送消息会报错,但是在报错之前,runtime system会给接受消息的对象第二次机会去处理这条消息.
报错之前,runtime会向对象,发送一条只带有一个NSInvocation对象参数的forwardInvocation:消息.NSInvocation对象内部封装了传递过来的原始的消息和参数.
可以通过实现forwardInvocation:方法给这个消息一个默认的响应,或者其他方式避免报错.如名所示,forwardInvocation通常被用来将消息传递给另外一个对象.
Even if your class can’t inherit a method,you can still “borrow” it by implementing a version of the method that simply passes the message on to an instance of the other class:
-(id)negotiate
{
if([someOtherObject respondsTo:@selector(negotiate)])
return [someOtherObject negotiate];
return self;
}
这样需要实现每一个需要跨类调用的方法,并且当添加了新类和新方法的时候,这里也需要做相应的修改.
dynamic rather than static
工作机制如下:
当一个对象不能响应selector所对应的消息的时候,runtime system 想该对象发送一条forwardInvocation:.每个对象都从NSObject 类继承了一个forwardInvocation:方法,但是NSObject中的该方法只是调用了doesNotRecognizeSelector:方法.在继承的类中重写forwardInvocation:方法,可以进一步提供传递消息给其他类的方法.
为了传递消息,所有的forwardInvocation:方法需要做如下工作:明确消息发送到哪.
将原始参数发动至那里
传递消息可以通过invokeWithTarget:方法发送:
forwardInvocation:的实现:
-(void)forwardInvocation:(NSInvocation *)anInvocation
{
if([someOtherObject respondsToSelector:[anInvocation selector]])
[anInvocation invokeWithTarget:someOtherObject];
else
[super forwardInvocation:anIncation];
}
Forwarding mimics inheritance can be used to lend some of the effects of multiple inheritance to Objective-C programs.