3

我正在将一个项目移植到 iPhone(来自 Windows Mobile),并使用 Objective-C++ 尽可能多地共享通用 C 和 C++ 代码。但是,在测试过程中,我偶然发现了一个奇怪且麻烦的问题,该问题仅在设备上运行时才会出现。我已将问题代码提炼到一个新项目中,以证明可重复性并允许轻松共享。

// MemoryTestAppDelegate.mm
#include "MemoryTestAppDelegate.h"
#include "Widget.h"

@implementation MemoryTestAppDelegate

@synthesize window;

- (void)applicationDidFinishLaunching: (UIApplication*)application {
    Widget widget;
    const wchar_t wideHello[] = L"Hello, world!";
    const char narrowHello[] = "Hello, world!";
    widget.Go();
    widget.Go(wideHello);

    [window makeKeyAndVisible];
}

- (void)dealloc {
    [window release];
    [super dealloc];
}

@end

 

// MemoryTestAppDelegate.h
#import <UIKit/UIKit.h>

@interface MemoryTestAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow* window;
}

@property (nonatomic, retain) IBOutlet UIWindow* window;

@end

 

// Widget.h
#include <iostream>

class Widget {
public:
    Widget() { };
    ~Widget() { };

    void Go() const { std::wcout << L"Widget is GO." << std::endl; };
    void Go(const wchar_t* message) const { std::wcout << message << std::endl; };
};

 

// main.mm
#import <UIKit/UIKit.h>

int main(int argc, char* argv[]) {
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, @"MemoryTestAppDelegate");
    [pool release];
    return retVal;
}

 

其余项目文件以及设置是通过创建新的基于 iPhone Window 的应用程序默认提供的。(我通过删除 .xib 删除了 Interface Builder,从 MemoryTest-Info.plist 中删除了“主 nib 文件基本名称”,并将 @“MemoryTestAppDelegate”指定为 main.mm 中 UIApplicationMain 的第四个参数。)

模拟器按预期运行此示例,但设备出现了我的问题:单步执行 applicationDidFinishLaunching 中的代码,Widget 对象按预期构建。但是,wideHello 和 narrowHello 在 Locals 观察区域中似乎都已损坏。(wideHello 不显示,但显示了正确的字符数,narrowHello 显示为“`K3\x10f\x11”。)检查内存窗口中的两个字符串,可以看到正确的内容 - 超出假定地址 64 个字节wideHello 和narrowHello 的。

如对重载方法 Widget::Go(const wchar_t*) const 的第二次调用所示,wideHello 字符串通过 std::wcout 显示,并且在单步执行 applicationDidFinishLaunching 时正确输出字符串!但是,使用 wcscpy/memcpy 从实际内容前 64 字节的“pre”数据中读取的复制操作会导致我在实际设备上的应用程序出现许多问题。如果我用 Widget* 和动态分配替换在本地堆栈上初始化 Widget,则内存布局符合预期。我尝试了其他变体,但似乎只有堆栈分配的 C++ 对象会导致问题。

任何信息将不胜感激,感谢阅读。

4

1 回答 1

1

甚至苹果自己也承认他们的模拟器和设备之间存在一些差异。

遗憾的是,我无法帮助您解决问题,但请记住,模拟器代码在您的 Mac 处理器上编译和运行,如在您的英特尔、i386 架构上编译和运行,当您为设备编译时,它完全不同,编译使用设备的armv6。

您发现的任何听起来像是 i386 拱形问题的怪癖可能永远不会出现在设备上,反之亦然。

于 2010-02-16T19:12:36.907 回答