method_exchangeImplementations导致EXC_BAD_ACCESS错误

时间:2015-12-14 15:10:54

标签: ios objective-c runtime

我试图测试method_exchangeImplementations在不同情况下的行为方式。当我尝试使用代码时,出现了EXC_BAD_ACCESS错误。我不知道为什么程序以此错误结束。这是我项目中的代码:



#import "ViewController.h"
#import <objc/runtime.h>


@interface Person : NSObject
@end

@implementation Person

- (void)say{
    NSLog(@"Person");
}

@end

@interface Student : Person
@end

@implementation Student


- (NSString *)say {
    return nil;
}

@end


@interface Doctor : Person

@end

@implementation Doctor


@end


@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    Student *stu =[Student new];
    Doctor *dr = [Doctor new];
    Person *person = [Person new];
    Method studentMethod = class_getInstanceMethod([Student class], @selector(say));
    Method doctorMethod = class_getInstanceMethod([Doctor class], @selector(say));


    [stu say];
    [dr say];
    method_exchangeImplementations(studentMethod, doctorMethod);
 
    [stu say];
    [dr say];
    [person say];
}


@end
&#13;
&#13;
&#13;

我必须提到的一件事是Student类中的-say方法。 say方法的返回值是NSString *。我不知道是否允许使用不同的返回类型编写覆盖方法。至少,编译器并没有阻止我这样做,也许它仍然认为它是一个普通的覆盖。

有人能让我摆脱这个错误吗?请解释为什么编译器允许使用不同的返回类型覆盖。谢谢!

1 个答案:

答案 0 :(得分:1)

编译器(和ARC)倾向于始终保留swizzled方法的返回值。当返回的值不是NSObject时,它通常会导致EXC_BAD_ACCESS(因为它将retain消息发送到非objC实例)。

如果你交换的一个方法需要返回一个非objC值(int,C string等等,甚至是一个void),那么在方法调用时强制转换函数指针会让编译器知道它不应该保留它(这避免了崩溃)。有关详细信息,请参阅https://blog.newrelic.com/2014/04/16/right-way-to-swizzle/的第二个脚注。

我希望这会有所帮助,在找到拯救我生命的意想不到的脚注之前,我已经失去了几天(和晚上)!