__unsafe_unretained NSString struct var

时间:2012-08-08 03:07:54

标签: iphone ios struct nsstring

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

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

ARC forbids Objective-C objects in structs or unions

因此,阅读有关错误的信息,我认为添加

是明智的
__unsafe_unretained
在NSString声明之前

但是我不知道这会产生什么影响,我已经快速阅读并发现了这个详细的post关于

的差异
  • __强
  • __弱
  • __ unsafe_unretained

然而,对于一个带有__unsafe_unretained的结构中的NSString是什么仍然有点模糊,并希望有人可以告诉我发生了什么以及我将来需要考虑的内存和停止任何内容泄漏。

任何帮助将不胜感激。

4 个答案:

答案 0 :(得分: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函数......这可能在你作为二进制文件获得的一些静态库中。

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

使这项工作可靠地非常非常困难。相反,ARC的创造者只是放弃了并说“忘了它。我们不会允许您在结构中添加__strong__weak引用。“

这就是为什么如果使用__unsafe_unretained告诉ARC“不要尝试管理这个引用的对象的所有权”,你只能将对象指针放入结构中。

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

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

答案 1 :(得分:3)

更多值得思考的东西......

如果你真的需要非Objective-c代码中的ARC指针,你可以在C ++中原生使用它们。

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

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

std::list<UIView*> views;

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

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

答案 2 :(得分:2)

ARC非常喜欢抱怨!实际上,我们必须从历史角度来看待这个问题。在旧版手动参考计数环境中,编译器并没有抱怨,因为它知道所有与内存相关的内容都是你的工作,而你的工作就是这样。但是当Apple引入自动引用计数时,情况发生了变化,因为编译器需要更多地了解对象的类型和包含的内容,以便它知道如何有效地正确管理所述对象的内存。当你将一个Objective-C对象放入一个C-struct时,你就会在编译器上伸出舌头,因为一个struct意味着你自己拥有并管理它内部项目的内存(那和ARC没有触及malloc和free)。这就是__unsafe_unretained的用武之地。有了它,我们告诉编译器任何和所有的内存操作都是你的责任,就像在MRC中一样。 ARC字面上并不能保证安全&#34;取消分配后对象的指针为nil,因此它会让你明确地声明它。

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

答案 3 :(得分:-3)

不要将目标C对象放在结构中。这就是为什么Obj C支持课程。你正在编码C.