2015-12-14 5 views
1

Я пытался проверить, как поведение метода_exchangeImplementations ведет себя в разных ситуациях. Когда я попробовал следующий код, у меня появилась ошибка EXC_BAD_ACCESS. Я не знаю, почему программа закончилась этой ошибкой. Вот код в моем проекте: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

Существует одна вещь, которую я должен упомянуть, что является -say метод в классе Student. Возвращаемое значение метода say - NSString *. Я не могу разрешить использование метода переопределения с другим типом возврата. По крайней мере, компилятор не мешал мне это делать, возможно, он все еще считает это нормальным переопределением.

Может ли кто-нибудь убрать меня с этой ошибки? Пожалуйста, объясните, почему компилятор допускает переопределение с другим типом возврата. Благодаря!

+0

Просто добавьте одну вещь, ошибка отображается в строке второго вызова экземпляра stu. – Evan

+0

Вы изменили реализации метода, но не изменили кодировку типа метода. –

+0

@ Cy-4AH Это имеет смысл. Я попробую. Спасибо. – Evan

ответ

1

Компилятор (и ARC) имеет тенденцию всегда сохранять возвращаемое значение swizzled метода. Он часто вызывает EXC_BAD_ACCESS, когда возвращаемые значения не являются объектами NSObject (потому что он отправляет сообщение retain экземпляру, отличному от objC).

Если один из ваших методов обмена должен возвращать значение non-objC (int, строка C и т. Д.) Или даже пустоту), приведение указателя функции в вызов метода позволяет компилятору знать, что он не должен его сохранять (что позволяет избежать сбоя). См. Вторую сноску https://blog.newrelic.com/2014/04/16/right-way-to-swizzle/ для получения дополнительной информации.

Надеюсь, это поможет, я потерял дни (и ночи), прежде чем найти эту неожиданную сноску, которая спасла мою жизнь!