3

我正在尝试创建一个结构,其中包含几个不同类型的不同变量。

有几种类型是 NSString,但尝试这样做会导致错误

ARC forbids Objective-C objects in structs or unions

因此,在阅读了有关该错误的信息后,我认为添加该错误是明智的

__unsafe_unretained

在 NSString 声明之前,但是我不知道这会产生什么后果,我快速阅读并找到了这篇关于差异的详细帖子

  • __强的
  • __虚弱的
  • __unsafe_unretained

但是,对于前面带有 __unsafe_unretained 的结构中的 NSString 发生了什么仍然有点模糊,并希望有人能告诉我发生了什么以及我将来需要考虑的关于内存和阻止任何泄漏的事情。

任何帮助,将不胜感激。

4

4 回答 4

10

假设,在 ARC 下,你可以声明一个这样的结构:

typedef struct {
    __strong NSObject *someObject;
    int someInteger;
} MyStruct;

然后你可能会写这样的代码:

MyStruct *thing = malloc(sizeof(MyStruct));

问题:malloc不会将它返回的内存填零。一些随机值也是如此thing->someObject- 不一定是NULL。然后像这样为它分配一个值:

thing->someObject = [[NSObject alloc] init];

在幕后,ARC 会将其转换为如下代码:

NSObject *temporary = [[NSObject alloc] init];
[thing->someObject release];
thing->someObject = temporary;

这里的问题是您的程序只是发送release了一些随机值!此时您的应用程序可能会崩溃。

您可能会说 ARC 应该识别调用malloc并注意设置someObject为 NULL 以防止这种情况发生。问题是它malloc可能包含在其他一些函数中,如下所示:

void *myAllocate(size_t size) {
    void *p = malloc(size);
    if (!p) {
        // malloc failed.  Try to free up some memory.
        clearCaches();
        p = malloc(size);
    }
    return p;
}

好的,现在 ARC 也必须知道你的myAllocate函数......这可能在你作为二进制文件获得的某个静态库中。

您的应用程序甚至可能有自己的内存分配器,可以回收旧的分配,而无需每次都使用free和。malloc因此,即使malloc在返回之前更改为零填充内存也行不通。ARC 必须知道程序中的任何自定义分配器。

使这项工作可靠地工作将非常非常困难。所以相反,ARC 的创造者只是放弃了,说“算了。我们不会让你在结构中放置__strong__weak引用。”</p>

这就是为什么只有__unsafe_unretained在告诉 ARC“不要尝试管理 this 引用的对象的所有权”时才能将对象指针放入结构体中。</p>

您可以尝试使用包含__unsafe_unretained对象引用的结构,也许使用CFRetainandCFRelease手动保留和释放它们。然后您可以创建一个此类结构的数组。这很容易出错,因此只有在分析器告诉您它对性能至关重要时,您才应该这样做。

相反,只需创建一个新的 Objective-C 类而不是结构。@property为您将放入结构中的每个字段分配一个类。使用 anNSMutableArray来管理这个新类的实例数组。

于 2012-08-08T04:23:58.210 回答
4

只是更多的思考...

如果您真的需要在非目标 c 代码中使用 ARC 指针,您可以在 C++ 中本地使用它们。

事实上,您可以将 ARC 指针存储在所有标准模板容器中,并且它们仍然保留(哈哈)它们正确的语义。

struct Foo {
    NSDictionary *dictionary;
    NSString *string;
    __weak UIViewController *viewController;
};

std::list<UIView*> views;

由于编译器将 ARC 指针视为具有非平凡构造函数的对象,因此它们可以具有正常的语义。

他们所有的 ARC 荣耀都将被神奇地处理。

于 2012-08-08T04:47:35.740 回答
2

ARC就是喜欢抱怨!实际上,我们必须从历史角度来看。在很久以前的老式手动引用计数环境中,编译器并没有抱怨,因为它知道所有与内存相关的事情都将是你的工作,而且只有你自己的工作。但是当 Apple 引入自动引用计数时,情况发生了变化,因为编译器需要更深入地了解对象的类型和包含的内容,以便知道如何有效地正确管理所述对象的内存。当您将 Objective-C 对象放入 C-struct 时,您有点在向编译器伸出舌头,因为 struct 意味着您将自己拥有和管理其中项目的内存(而 ARC 不不要碰 malloc 和 free)。那是哪里__unsafe_unretained进来。有了它,我们告诉编译器任何和所有内存操作都将是你的责任,就像在 MRC 中一样。ARC 字面意思是“不能保证对象指针在释放后为零的安全性”,所以它让你明确声明它是这样的。

如果你想避免所有这些废话,只需将你的结构变成一个轻量级的类并正常声明你的对象。毕竟,Objective-C 中的类只是 C-structs-(ish),其中包含了很多 Apple 的魔法。

于 2012-08-08T03:51:49.910 回答
-3

不要将目标 C 对象放在结构中。这就是 Obj C 支持类的原因。您正在编写 C 代码。

于 2012-08-08T03:21:12.030 回答