Xcode4中新的LLVM编译器是否会使类继承无法正常工作?
编辑:问题解决了!清理并重新启动后它就消失了!我不知道是什么原因造成的!
这已经让我头疼了一整天:
在 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
的一个实例。它调用 TheSuperclass
的 init 方法,给我 NSLogs。
现在真正奇怪的部分是:当我“从外部”调用 TheSubclass 对象上的该方法时,它起作用了:
TheSubclass *foo = [[TheSubclass alloc] init];
id bar = [foo returnSomethingUseful];
// Getting the NSLog: "Correct method called!"
所以强调一下:当我从 TheSuperclass 的实现中调用 [self returnSomethingUseful]
时,它调用错误的实现(这是超类的实现,而不是子类中被覆盖的实现。
那么我该如何解决这个问题?这可能来自哪里?这是运行时的问题吗,可能是由错误引起的在编译器中?
EDIT: Problem solved! After cleaning and rebooting it just disappeared! I don't know what caused this!
This has caused me headaches for a full day now:
In Xcode 3.2 everything worked excellent. Then I switched to 4.2 and suddenly a class inheritance does not work anymore.
I have a class TheSuperclass
and TheSubclass : TheSuperclass
. To simplify testing, I really created them like this. There's no more code than what you can see here:
// 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
declares a template method, that is, a method which just does nothing, returns nil and is intended for subclassing:
- (id)returnSomethingUseful {
NSLog(@"Dude, you have to override -returnSomethingUseful");
return nil; // subclasses override this method!
}
In TheSubclass
, I simply override that template method. And of course I COPIED the implementation out of TheSuperclass
to get it 100% right. No typo. That's a checked fact. Looks like this:
- (id)returnSomethingUseful {
NSLog(@"Correct method called!");
return usefulObject;
}
In the implementation of TheSuperclass
a piece of code calls [self returnSomethingUseful]
in order to get that object from the template method. It's a great pattern and I have used it a lot. It always worked exactly like this.
But now it appears that even though I create an instance of TheSubclass
, it always calls the WRONG method. The one from TheSuperclass, instead of the one it should (which is the overwriding method of course)
I've checked that at least 100 times! Seriously, it is an instance of TheSubclass
. It calls the init method of TheSuperclass
giving me NSLogs.
Now the really strange part: When I call that method on my TheSubclass object "from outside", it works:
TheSubclass *foo = [[TheSubclass alloc] init];
id bar = [foo returnSomethingUseful];
// Getting the NSLog: "Correct method called!"
So to emphasize it: When I call [self returnSomethingUseful]
from within the implementation of TheSuperclass, it calls the WRONG implementation (which is the one of the superclass, rather than the overwritten one in the subclass.
So how can I work around this? Where does this possibly come from? Is this a problem in the runtime, maybe caused by an error in the compiler?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
LLVM 显然能够正确实现简单的子类化。每天都有成千上万的程序使用它,因此如果您正在编写标准代码(不尝试任何棘手或未记录的内容),那么这不是一个需要解决的问题。以下是您应该做的事情:
[self class]
以确保您确实是您所认为的那样。isa
指针(很容易找到;在代码中搜索->isa
)。init
。这是最有可能做一些过于棘手的事情的地方。确保您遵循简单的模式。LLVM clearly is able to implement simple subclassing correctly. Thousands of programs use it every day, so this is not a problem to be worked around if you are writing standard code (not trying anything tricky or undocumented). Here are the things you should do:
[self class]
to make sure you really are what you think you are.isa
pointer (easy to find; search for->isa
in your code).init
. This is the most likely place to have done something over-tricky. Make sure you're following the simple patterns.如果编译器搞砸了如此基本的东西,系统将无法启动。
在您的
init
方法中断言该类,因为您有 TheSuperclass 的实例,或者某些内容拼写错误。If the compiler screwed up something so basic, the system wouldn't boot.
Assert the class in your
init
method because either you have an instance of TheSuperclass or something is misspelled.这个术语是“覆盖”,而不是“覆盖”。
您没有向我们展示足够的代码来了解问题所在。向我们展示这两个类的 -init 方法,并向我们展示您的子类实例的创建位置。
The term is "override", not "overwrite".
You haven't shown us enough of your code to know what the problem is. Show us the -init methods for both classes, and show us where your instance of the subclass is being created.