method_exchangeImplementations 导致 EXC_BAD_ACCESS 错误

问题描述 投票:0回答:1

我试图测试 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

有一点不得不提,那就是Student类中的-say方法。 say方法的返回值是NSString *。我不知道是否允许使用不同的返回类型编写重写方法。至少,编译器没有阻止我这样做,也许它仍然认为它是正常的覆盖。

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

ios objective-c runtime
1个回答
2
投票

编译器(和 ARC)倾向于始终保留 swizzled 方法的返回值。当返回值不是 NSObject 时,它通常会导致 EXC_BAD_ACCESS (因为它将

retain
消息发送到非 objC 实例)。

如果交换的方法之一需要返回非 objC 值(int、C 字符串等...甚至是 void),则在方法调用时强制转换函数指针可以让编译器知道它不应保留它(这可以避免碰撞)。有关更多信息,请参阅https://blog.newrelic.com/2014/04/16/right-way-to-swizzle/此处存档版本)的第二个脚注。

我希望这会有所帮助,在找到这个意外的脚注拯救了我的生命之前,我已经损失了几天(和几夜)!

© www.soinside.com 2019 - 2024. All rights reserved.