objective-c - 为什么释放我的阵列会使我的应用程序崩溃?

标签 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];
    }

最佳答案

让我们一步一步来
键: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:

...[returns] nil if the file can’t be opened or the contents of the file can’t be parsed into an array


这减少了一些麻烦并使该方法更易于阅读。我还将变量名称扩展为有意义的名称(个人喜好)。
我还将该方法重命名为 load art 是多余的,因为本质上您正在返回系统详细信息,事实上它们正在被加载并不是方法调用者真正关心的问题。
同样重要的是要注意,其他答案建议您进行额外的保留/复制,然后记得稍后释放返回的结果。这违反了 cocoa 约定,因为方法名称不包含 new/init/copy,因此该方法的调用者不应最终拥有结果。

关于objective-c - 为什么释放我的阵列会使我的应用程序崩溃?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8115644/

相关文章:

ios - 如何在 iOS 的 Collection View 中从底部删除多余的空间?

ios - UITableView 在 TabBar 下

ios - 将对象添加到 NSMutableArray 将不起作用

ios - 想要为另一个帐户更新 Itunesconnect 中的 ipa 文件

objective-c - NSArray 的实际类是什么?

iphone - 如何将 NSArray 输出连接到以逗号分隔的 NSString

ios - 设置一个类 IBOutlet 引用另一类文本字段的导出?

ios - 使用 UIIImagePicker 的 CGAffineTransform 缩放 UIImage 并保存到解析 SDK

ios - NSLog数组描述,不是内存地址

ios - 如何使用 Swift 保持数据源与 firebase 实时数据库同步?