Xcode4中新的LLVM编译器是否会使类继承无法正常工作?

发布于 2024-12-09 21:35:53 字数 2717 浏览 0 评论 0原文

编辑:问题解决了!清理并重新启动后它就消失了!我不知道是什么原因造成的!

这已经让我头疼了一整天:

在 Xcode 3.2 中一切都工作得很好。然后我切换到 4.2,突然类继承不再起作用了。

我有一个类 TheSuperclassTheSubclass : 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

幼儿园老大 2024-12-16 21:35:53

LLVM 显然能够正确实现简单的子类化。每天都有成千上万的程序使用它,因此如果您正在编写标准代码(不尝试任何棘手或未记录的内容),那么这不是一个需要解决的问题。以下是您应该做的事情:

  • 重新启动。 Xcode 假装您在安装后无需重新启动。根据我的经验,你确实如此。解决了升级Xcode后90%的问题。
  • 清理并重建。这不太可能修复它,因为从 3.2 到 4.2 无论如何都会将派生文件放在完全不同的位置。但这值得尝试。
  • 检查[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:

  • Reboot. Xcode pretends that you don't have to reboot after install. You do in my experience. It solves 90% of problems after upgrading Xcode.
  • Clean and rebuild. This is less likely to fix it because going from 3.2 to 4.2 puts the derived files in completely different places anyway. But it's worth trying.
  • Check [self class] to make sure you really are what you think you are.
  • Verify that you never mess with the isa pointer (easy to find; search for ->isa in your code).
  • Check your init. This is the most likely place to have done something over-tricky. Make sure you're following the simple patterns.
  • Derive the simplest form of the problem and post some code that demonstrates it. From your description, this should be possible to do in very few lines of code. Attempting to create this simplified version will more often than not show you where your mistake is.
话少情深 2024-12-16 21:35:53

如果编译器搞砸了如此基本的东西,系统将无法启动。

在您的 init 方法中断言该类,因为您有 Th​​eSuperclass 的实例,或者某些内容拼写错误。

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.

遮云壑 2024-12-16 21:35:53

这个术语是“覆盖”,而不是“覆盖”。

您没有向我们展示足够的代码来了解问题所在。向我们展示这两个类的 -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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文