使用运行时库覆盖方法

时间:2013-05-09 11:34:59

标签: iphone ios objective-c runtime objective-c-runtime

对于在此方法中添加- (void)viewWillAppear:(BOOL)animated的所有ViewControllers,我需要覆盖NSLog(@"blabla")。即每次调用viewWillAppear后都会调用实现的viewWillAppear +我的NSLog消息的早期实现。可能吗?如果是,请给我一个建议。

目前我已尝试过此代码

@implementation RuntimeTest

IMP previusImp;
IMP newIMP;
- (void)ovverrideViewWillAppearInViewController:(Class)vcClass {
    newIMP = class_getMethodImplementation([self class], @selector(viewWillAppear:));
    Method viewWillAppearMethod = class_getInstanceMethod(vcClass, @selector(viewWillAppear:));
    previusImp = method_setImplementation(viewWillAppearMethod, newIMP);
}

- (void)viewWillAppear:(BOOL)animated {
    previusImp(self, @selector(viewWillAppear:), animated);
    NSLog(@"log2");
}

@end

然后我

@implementation IRViewController2

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    NSLog(@"log");
}

@end

我的自定义viewWillAppear首先调用,然后viewWillAppear调用IRViewController2。在此之后我的应用程序崩溃了EXC_BAD_ACCESS。怎么了?

1 个答案:

答案 0 :(得分:2)

如果你不能使用子类,因为你想全局地做,但也不想丢失方法的旧版本(所以类别覆盖是不可能的)那么你需要{{3旧方法,放入你的新方法,然后调用旧方法...我过去使用了一个名为swizzle away的东西来执行此操作,它可以轻松调整而无需编写一堆运行时代码

if (![self jr_swizzleMethod:@selector(originalInit) withMethod:@selector(init) error:&err])
{
    NSLog(@"unable to jr_swizzle methods, error: %@",err);
    exit(EXIT_FAILURE);
}
if (![self jr_swizzleMethod:@selector(init) withMethod:@selector(myInit) error:&err])
{
    NSLog(@"unable to jr_swizzle methods, error: %@",err);
    exit(EXIT_FAILURE);
}

然后您的-myInit方法可以调用-originalInit或您正在使用的任何方法。