Iphone __不安全\u未恢复的NSString结构变量

Iphone __不安全\u未恢复的NSString结构变量,iphone,ios,struct,nsstring,Iphone,Ios,Struct,Nsstring,我试图创建一个结构,其中包含几个不同类型的不同变量 有几种类型是NSString,但尝试这样做会导致错误 ARC禁止结构或联合中的Objective-C对象 因此,在阅读了有关错误的内容后,我认为添加以下内容是明智的 __unsafe_unretained 然而,在NSString声明之前,我不知道这会产生什么后果,我已经快速阅读了一遍,发现了关于 __强壮的 __软弱的 __不安全的 然而,对于一个结构中的NSString(其前面有“不安全的”未恢复)发生了什么,它仍然有点含糊不清,希望

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

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

ARC禁止结构或联合中的Objective-C对象

因此,在阅读了有关错误的内容后,我认为添加以下内容是明智的

__unsafe_unretained
然而,在NSString声明之前,我不知道这会产生什么后果,我已经快速阅读了一遍,发现了关于

  • __强壮的
  • __软弱的
  • __不安全的
然而,对于一个结构中的NSString(其前面有“不安全的”未恢复)发生了什么,它仍然有点含糊不清,希望有人能告诉我发生了什么,以及关于内存和阻止任何泄漏,我将来需要考虑什么


任何帮助都将不胜感激。

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

ARC只是喜欢抱怨!事实上,我们必须从历史的角度来看这一点。在旧式的手动引用计数环境中,编译器并没有抱怨,因为它知道所有与内存相关的内容都将是您的工作,而您的工作是单独的。但当苹果公司引入自动引用计数时,情况发生了变化,因为编译器需要对对象的类型和包含的内容进行更多的分析,以便知道如何有效地管理该对象的内存。当您将Objective-C对象放入C-struct中时,您在某种程度上是在向编译器伸出舌头,因为struct意味着您将自己拥有并管理其中项目的内存(这和ARC不涉及malloc和free)。这就是
\uuuuuuunsared\uunretained
的用武之地。有了它,我们告诉编译器,任何和所有内存操作都是您的责任,就像在MRC中一样。ARC字面上的意思是“不能保证安全”,对象的指针在解除分配后为零,因此它使您显式地声明为零


如果您想避免所有这些胡说八道,只需将结构转换为轻量级类并正常声明对象即可。毕竟,Objective-C中的类只是C-structs-(ish),其中加入了很多苹果魔法。

假设在ARC下,您可以声明如下结构:

typedef struct {
    __strong NSObject *someObject;
    int someInteger;
} MyStruct;
MyStruct *thing = malloc(sizeof(MyStruct));
thing->someObject = [[NSObject alloc] init];
NSObject *temporary = [[NSObject alloc] init];
[thing->someObject release];
thing->someObject = temporary;
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;
}
然后您可以编写如下代码:

typedef struct {
    __strong NSObject *someObject;
    int someInteger;
} MyStruct;
MyStruct *thing = malloc(sizeof(MyStruct));
thing->someObject = [[NSObject alloc] init];
NSObject *temporary = [[NSObject alloc] init];
[thing->someObject release];
thing->someObject = temporary;
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;
}
问题:
malloc
不能将返回的内存归零。所以
thing->someObject
是一些随机值,不一定为空。然后按如下方式为其赋值:

typedef struct {
    __strong NSObject *someObject;
    int someInteger;
} MyStruct;
MyStruct *thing = malloc(sizeof(MyStruct));
thing->someObject = [[NSObject alloc] init];
NSObject *temporary = [[NSObject alloc] init];
[thing->someObject release];
thing->someObject = temporary;
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会将其转换为如下代码:

typedef struct {
    __strong NSObject *someObject;
    int someInteger;
} MyStruct;
MyStruct *thing = malloc(sizeof(MyStruct));
thing->someObject = [[NSObject alloc] init];
NSObject *temporary = [[NSObject alloc] init];
[thing->someObject release];
thing->someObject = temporary;
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;
}
这里的问题是,您的程序刚刚将
release
发送到某个随机值!此时,您的应用程序可能会崩溃

您可能会说ARC应该识别对
malloc
的调用,并注意将
someObject
设置为NULL以防止出现这种情况。问题在于
malloc
可能被包装在其他函数中,如下所示:

typedef struct {
    __strong NSObject *someObject;
    int someInteger;
} MyStruct;
MyStruct *thing = malloc(sizeof(MyStruct));
thing->someObject = [[NSObject alloc] init];
NSObject *temporary = [[NSObject alloc] init];
[thing->someObject release];
thing->someObject = temporary;
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的创建者放弃了,他们说:“算了吧,我们不会让你把
\uuuuu strong
\uu弱
引用放在结构中。”

这就是为什么只有在使用
\uu unsafe\u unrepaired
告诉ARC“不要试图管理此引用对象的所有权”时,才能将对象指针放入结构中

您可以尝试使用包含
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。然后可以创建这样的结构的数组。这很容易出错,因此只有当探查器告诉您这对性能至关重要时,您才应该这样做


相反,只需创建一个新的Objective-C类而不是结构。为类指定一个
@property
,该属性对应于要放入结构中的每个字段。使用一个
NSMutableArray
来管理这个新类的一个实例数组。

更值得思考

如果你真的需要非Objto-C代码中的弧指针,你可以在C++中使用它们。 事实上,您可以在所有标准模板容器中存储弧指针,并且它们仍然保留(哈哈)其正确的语义

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

std::list<UIView*> views;
structfoo{
NSDictionary*字典;
NSString*字符串;
__弱UIViewController*viewController;
};
std::列表视图;
由于编译器将弧指针视为具有非平凡构造函数的对象,因此它们可以具有正常的语义

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

std::list<UIView*> views;

它们所有的弧光都会被神奇地处理。

让我困惑的可能是,我想创建一个包含类中初始化变量的对象数组。。我原计划只创建一个变量结构,然后在数组中使用该结构。。没有结构我怎么能做到这一点?类是由目标C中的类包含的,而不是结构。我想让我困惑的是如何创建一个包含变量的类数组。类只是结构,尽管有更奇特的编译器废话。用C语言编码有什么问题?我可以编写一个NSString或一个NSCFString,它不会对编译器产生任何影响(通过适当的强制转换)。很明显,这不是问题的目的。类不是“只有一点Ap的C结构”