3

我遇到了一个问题,即我的 iOS 应用程序在退出时崩溃,我已将其范围缩小到:

// File.h

struct Name {
    NSString *name;
}

// File.mm

Name names[] = {
    @"foo",
    @"bar",
};

当应用程序退出(按下 iPad 上的主页按钮)时,我遇到了objc_msgSend一个EXC_BAD_ACCESS (SIGSEGV). 它正在发生析构函数Name::~Name()

0   libobjc.A.dylib         0x37586e3a objc_release + 10
1   MyApp                   0x0014abfc Name::~Name() (NameManager.h:21)
2   MyApp                   0x0014ab42 Name::~Name() (NameManager.h:21)
3   MyApp                   0x0014ad94 __cxx_global_array_dtor + 120
4  libsystem_c.dylib        0x36bba1cc __cxa_finalize + 216
5  libsystem_c.dylib        0x36b854f6 exit + 6

请记住,这是在一个 .mm 文件中,因此它被编译为 obj-c++。

这已经好几个月了。我不知道它是什么时候开始发生的,但我怀疑是我更新到 xcode 4.4 的时候。

NSString文字应该受到保护(或一直受到保护)免受多个版本的影响,但我认为无论如何这里都不会发生这种情况。

有谁知道 xcode 4.4 中是否发生了一些变化?

我可以通过执行以下操作来修复崩溃:

struct Name {
    __unsafe_unretained NSString *name;
}

但我讨厌在不理解为什么以前有效的方法不再有效的情况下这样做。或者也许它永远不应该奏效。我也担心内存被覆盖,所以这可能只是一个症状。

这发生在 DEBUG 和 RELEASE 中。

更新:我在 ~Name() 中放置了一个断点并验证内存没有损坏。LLDB 能够转储 NSString OK。但是当我踩到它时它崩溃了。

4

1 回答 1

1

当您在 Objective-C++ 中声明一个包含启用了 ARC 的 Objective-C 对象的“普通旧数据”struct时,编译器有义务提供一个析构函数来正确释放结构的 ObjC 成员,即使您自己没有编写它们.

此限制不适用于 Objective-C++。但是,非平凡的所有权限定类型被认为是非 POD:在 C++11 术语中,它们不是平凡的默认可构造、可复制构造、可移动构造、可复制分配、可移动分配或可破坏的。使用 ARC 之外的类违反 C++ 的单一定义规则,在 ARC 下,该类将具有非平凡的所有权限定成员。

当您声明 Name 结构时,编译器会为您编写一个包含隐式强持有的 Objective-C 对象的析构函数。在执行时,这意味着 C++ 析构函数会擦除它所期望的 C++ 结构,而是结束指向字符串的指针。在没有有效指针的情况下,-releaseARC 在尝试取消引用不存在的接收器时会尝试发送段错误。

当您声明一个 Objective-C 成员__unsafe_unretained时,它告诉 ARC 将其从必须编写的析构函数中排除,因此该结构只是被销毁,并且-release永远不会发送。建议您将结构或类中的所有 Objective-C 对象标记为__unsafe_unretained并自己提供适当的内存管理,因为 ARC 会使跨语言的对象生命周期显着复杂化。

于 2014-05-21T16:34:41.240 回答