入门客AI创业平台(我带你入门,你带我飞行)
博文笔记

Message Forwarding + 动态绑定

创建时间:2016-01-04 投稿人: 浏览次数:396
> “unrecognized selector sent to instance …" 错误 动态绑定:objc_msgSend的实现,查找implementation表,最终是C函数形式的调用。
当某个类(以及继承树上的父类)编译时没有动态实现被调用的method的时候,一般情况下会被NSObject处理这个method(selector)并抛出异常。
我们有两种常用(三种)方法来动态的补充使得相应的lei可以处理此selector。
一种是动态方法手段(Dynamic Method Resolution),第二种是委托其他对象处理(Replacement Receiver)。下边通过例子直接说明。
============================================= NormalObject.h @interface NormalObject : NSObject
- (void)showMe;
// 实际上没有显式实现这个selector
- (void)testMe; @end
============================================== #import "NormalObject.h"
#import "ReplacementObject.h"
#import <objc/runtime.h>

#define kUseDynamicMethod YES

@interface NormalObject()
@property (strong, nonatomic) ReplacementObject *replacement;
@end

@implementation NormalObject

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.replacement = [[ReplacementObject alloc] init];
    }
    return self;
}

#pragma mark - Dynamic Method Resolution // 当且仅当未显示实现的selector被调用时,这里会被调用。- 再次调用同样的selector,这里不会被执行,因为已经cached了 + (BOOL)resolveInstanceMethod:(SEL)sel{
    if (kUseDynamicMethod) {
        NSString *selName = NSStringFromSelector(sel);         NSLog(@"required for: %@", selName); // 使用class_addMethod动态加入method,此后每次对testMe的调用都会直接调用impAddedMethod         class_addMethod(self, sel, (IMP)impAddedMethod, "v@:");
        return YES;
    } else {
        return NO;
    }
}

// must be a C method
void impAddedMethod(id self, SEL _sel){
    NSLog(@"You guy send an unknown selector!!!");
}

#pragma mark - Replacement Receiver
- (id)forwardingTargetForSelector:(SEL)aSelector{
    NSLog(@"%s called", __FUNCTION__);
    return self.replacement;
}

- (void)showMe{
    NSLog(@"NormalObject showMe called");
} @end ============================================== 辅助类: @interface ReplacementObject : NSObject
- (void)testMe; @end
@implementation ReplacementObject
- (void)testMe{
    NSLog(@"[ReplacementObject] Wahahahah, i implement this!");
} @end ============================================== 调用
    [obj1 showMe]; // 一般情况     [obj1 testMe]; // testMe没用命中,通过resolveInstanceMethod或forwardingTargetForSelector寻找解决方案,没有找到的话由NSObject来抛异常     NSLog(@"call it again");     [obj1 testMe]; // 第二次调用,resolveInstanceMethod不会再次触发,因为已经cached了。forwardingTargetForSelector则会每次都执行,因此Dynamic Method的效率会更高。
两者使用场景不同。Dynamic Method适用于@dynamic修饰的property的setter和getter的实现。Replacement Receiver适用于用composition模式来达到多重继承的效果。 阅读更多
声明:该文观点仅代表作者本人,入门客AI创业平台信息发布平台仅提供信息存储空间服务,如有疑问请联系rumenke@qq.com。
  • 上一篇:没有了
  • 下一篇:没有了
未上传头像