为什么发布我的数据会让我的应用崩溃?

时间:2011-11-13 23:28:58

标签: objective-c ios nsarray

如果我在将第一个数组复制到第二个数组后将其释放,我的应用程序崩溃了。如果我自动释放第一个阵列一切正常。为什么?有没有更好的方法将第一个数组复制到第二个数组?

如果我调用此方法,我会得到一个ECX_BAD_ACCESS,我传递一个空数组

-(NSArray *)loadSystemDetails
{
    AssortedCodeSnippets *acs = [[AssortedCodeSnippets alloc] init];
    NSArray *details;
    NSString *fp = [self tempPathAndFileName:[self systemDetailsFileName]];
    if ([acs fileExistsAtPath:fp]) {
        NSArray *array = [[NSArray alloc] initWithContentsOfFile:fp];
        details = array;
        [array release];
    } else {
        NSLog(@"No File to Load");
        CreateSystem *cls = [[CreateSystem alloc] init];
        details = [cls loadData];
        [cls release];
        [self saveDataFile:details toPath:fp];
    }
    NSLog(@"details: %@",details);
    [acs release];
    return details;
}

如果我自动释放阵列,它可以正常工作。

-(NSArray *)loadSystemDetails
{
    AssortedCodeSnippets *acs = [[AssortedCodeSnippets alloc] init];
    NSArray *details;
    NSString *fp = [self tempPathAndFileName:[self systemDetailsFileName]];
    if ([acs fileExistsAtPath:fp]) {
        NSArray *array = [[[NSArray alloc] initWithContentsOfFile:fp]autorelease];
        details = array;
    } else {
        NSLog(@"No File to Load");
        CreateSystem *cls = [[CreateSystem alloc] init];
        details = [cls loadData];
        [cls release];
        [self saveDataFile:details toPath:fp];
    }

3 个答案:

答案 0 :(得分:2)

让我们逐步完成这个

密钥:M =发布/保留消息,C =发布/保留消息的总和

                                                              // +----+---+
                                                              // | M  | C |
                                                              // +----+---+
NSArray *array = [[NSArray alloc] initWithContentsOfFile:fp]; // | +1 | 1 |
details = array;                                              // |  0 | 1 |
[array release];                                              // | -1 | 0 |
                                                              // +----+---+

此时你可以看到你将返回details,其数量为0,因此已经解除分配=崩溃。

复制是错误的术语,因为您实际上并不需要副本,因此您只希望指针details指向有效对象,因此以下内容会更正确

- (NSArray *)systemDetails
{
    NSString *filePath = [self tempPathAndFileName:[self systemDetailsFileName]];

    NSArray *details = [[[NSArray alloc] initWithContentsOfFile:filePath] autorelease];

    if (!details) {

        NSLog(@"No File to Load");
        CreateSystem *cls = [[CreateSystem alloc] init];
        details = [cls loadData];
        [cls release]; cls = nil;
        [self saveDataFile:details toPath:filePath];

    }

    NSLog(@"details: %@",details);

    return details;
}

我在这里利用NSArray的方法

  

initWithContentsOfFile:

     

... [return]如果无法打开文件或文件内容无法解析为数组,则返回

这减少了一些错误并使该方法更容易阅读。我还将变量名称扩展为有意义的名称(个人偏好)。

我还重命名了这个方法,因为load艺术是超级的,因为基本上你正在返回系统详细信息,它们被加载的事实并不是方法调用者真正关心的事实。

同样重要的是要注意,其他答案表明您需要额外的保留/复制,然后记得稍后发布返回的结果。这违反了cocoa约定,因为方法名称不包含new / init / copy,因此方法的调用者不应该最终拥有结果。

答案 1 :(得分:1)

在分配details指向retaindetails的{​​{1}}方法的结果时,发送array分配cls条消息。请务必-loadData方法之后的release details

答案 2 :(得分:1)

在您的代码示例中,您实际上并未将array复制到details。请记住,这两个变量都是指针到数组而不是数组本身。因此,行details = array只是将array的位置复制到details。换句话说,在这一行之后,两个变量都指向内存中完全相同的数组。因此,当您调用release时,内存中的对象将被释放,而 detailsarray现在都指向一个不存在的对象。如果要将数组实际复制到内存中,请使用

details = [array copy]

请记住,当你想摆脱这个对象时,最终你必须在release上调用details