Новый компилятор LLVM в Xcode4 заставляет наследование классов не работать должным образом? - PullRequest
1 голос
/ 17 октября 2011

РЕДАКТИРОВАТЬ: Проблема решена!После очистки и перезагрузки он просто исчез!Я не знаю, что вызвало это!

Это вызвало у меня головную боль на целый день:

В Xcode 3.2 все работало отлично.Затем я переключился на 4.2, и внезапно наследование классов больше не работает.

У меня есть класс TheSuperclass и TheSubclass : TheSuperclass.Чтобы упростить тестирование, я действительно создал их вот так.Там нет больше кода, чем вы можете увидеть здесь:

// TheSuperclass.h
@interface TheSuperclass : NSObject {

}

// subclasses must override this method
- (id)returnSomethingUseful;

@end

// TheSuperclass.m
#import "TheSuperclass.h"

@implementation TheSuperclass
- (id)returnSomethingUseful {
    NSLog(@"Dude, you have to override -returnSomethingUseful");
    return nil; // subclasses override this method!
}


- (id)init {
    if ((self = [super init])) {
            obj = [self returnSomethingUseful]; // TEST
        NSLog(@"TheSuperclass initialized: %@", obj);
    }
    return self;
}
@end

// TheSubclass.h
#import "TheSuperclass.h"

@interface TheSubclass : TheSuperclass {

}

@end

// TheSubclass.h
#import "TheSubclass.h"

- (id)returnSomethingUseful {
    NSLog(@"Correct method called!");
    return usefulObject;
}

TheSubclass *foo = [[TheSubclass alloc] init]; // remember: init of superclass calls the method
// Getting the NSLog: "Dude, you have to override -returnSomethingUseful"


id bar = [foo returnSomethingUseful]; // now call it directly on foo
// Getting the NSLog: "Correct method called!"

TheSuperclassобъявляет метод шаблона, то есть метод, который ничего не делает, возвращает nil и предназначен для подклассов:

- (id)returnSomethingUseful {
    NSLog(@"Dude, you have to override -returnSomethingUseful");
    return nil; // subclasses override this method!
}

В TheSubclass я просто переопределяю этот метод шаблона.И, конечно, я скопировал реализацию из TheSuperclass, чтобы сделать ее на 100% правильной.Нет опечатка.Это проверенный факт.Выглядит так:

- (id)returnSomethingUseful {
    NSLog(@"Correct method called!");
    return usefulObject;
}

В реализации TheSuperclass фрагмент кода вызывает [self returnSomethingUseful], чтобы получить этот объект из метода шаблона.Это отличный шаблон, и я много его использовал.Он всегда работал именно так.

Но теперь кажется, что, хотя я создаю экземпляр TheSubclass, он всегда вызывает метод НЕПРАВИЛЬНО.Тот из TheSuperclass, вместо того, который он должен (который, конечно, является методом переопределения)

Я проверял это по крайней мере 100 раз!Серьезно, это экземпляр TheSubclass.Он вызывает метод init TheSuperclass, давая мне NSLogs.

Теперь действительно странная часть: когда я вызываю этот метод для моего объекта TheSubclass "извне", он работает:

TheSubclass *foo = [[TheSubclass alloc] init];
id bar = [foo returnSomethingUseful];
// Getting the NSLog: "Correct method called!"

Чтобы подчеркнуть это: когда я вызываю [self returnSomethingUseful] изнутри реализации TheSuperclass, он вызывает реализацию WRONG (которая является суперклассом, а не перезаписанной в подклассе.

Так какя могу обойти это? Откуда это возможно? Это проблема во время выполнения, возможно, вызванная ошибкой в ​​компиляторе?

Ответы [ 3 ]

4 голосов
/ 17 октября 2011

LLVM ясно способен правильно реализовать простые подклассы. Тысячи программ используют его каждый день, так что это не проблема, если вы пишете стандартный код (не пытаясь сделать что-то хитрое или недокументированное). Вот что вы должны сделать:

  • Reboot. Xcode делает вид, что вам не нужно перезагружаться после установки. Вы делаете по моему опыту. Это решает 90% проблем после обновления Xcode.
  • Очистить и восстановить. Это менее вероятно исправить, потому что переход с 3.2 на 4.2 все равно помещает производные файлы в совершенно разные места. Но стоит попробовать.
  • Отметьте [self class], чтобы убедиться, что вы действительно то, что вы думаете.
  • Убедитесь, что вы никогда не путаетесь с указателем isa (его легко найти; найдите в своем коде ->isa).
  • Проверьте свой init. Это наиболее вероятное место, чтобы сделать что-то хитрое. Убедитесь, что вы следуете простым шаблонам.
  • Выведите простейшую форму проблемы и опубликуйте код, который ее демонстрирует. Из вашего описания, это должно быть возможно сделать в очень мало строк кода. Попытка создать эту упрощенную версию чаще всего покажет вам, где ваша ошибка.
2 голосов
/ 17 октября 2011

Если компилятор испортил что-то настолько простое, система не загрузится.

Утвердите класс в вашем методе init, потому что у вас есть экземпляр класса TheSuperclass или что-то написано с ошибкой.

1 голос
/ 17 октября 2011

Термин «перезаписать», а не «перезаписать».

Вы не показали нам достаточно своего кода, чтобы понять, в чем проблема.Покажите нам методы -init для обоих классов и покажите, где создается ваш экземпляр подкласса.

...