【问题标题】:Error while checking if a file exists检查文件是否存在时出错
【发布时间】:2010-11-24 03:37:24
【问题描述】:

我正在尝试使用 writeToFile 写入 plist 文件,在写入之前我会检查文件是否存在。

这是代码:

#import "WindowController.h"

@implementation WindowController

@synthesize contacts;

NSString *filePath;
NSFileManager *fileManager;

- (IBAction)addContactAction:(id)sender {

    NSDictionary *dict =[NSDictionary dictionaryWithObjectsAndKeys:
                         [txtFirstName stringValue], @"firstName",
                         [txtLastName stringValue], @"lastName",
                         [txtPhoneNumber stringValue], @"phoneNumber",
                         nil];

    [arrayContacts addObject:dict];

    [self updateFile];
}

- (void)awakeFromNib {
    NSString *rootPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    filePath    = [rootPath stringByAppendingPathComponent:@"Contacts.plist"];
    fileManager = [NSFileManager defaultManager];

    contacts = [[NSMutableArray alloc] init];

    if ([fileManager fileExistsAtPath:filePath]) {

        NSMutableArray *contactsFile = [[NSMutableArray alloc] initWithContentsOfFile:filePath];
        for (id contact in contactsFile) {
            [arrayContacts addObject:contact];
        }
    }
}

- (void) updateFile {
    if ( ![fileManager fileExistsAtPath:filePath] || [fileManager isWritableFileAtPath:filePath]) {
        [[arrayContacts arrangedObjects] writeToFile:filePath atomically:YES];
    }
}

@end

执行 addContactAction 时,我没有收到任何错误,但程序会停止,并将我带到调试器。当我在调试器中按继续时,我得到:

Program received signal:  “EXC_BAD_ACCESS”.

但这可能并不重要。

PS:我是 mac 编程的新手,我不知道还能尝试什么,因为我没有收到告诉我出了什么问题的错误消息。

文件的路径是:

/Users/andre/Documents/Contacts.plist

我之前尝试过这个(结果相同),但我读到您只能写入文档文件夹:

/Users/andre/Desktop/NN/NSTableView/build/Debug/NSTableView.app/Contents/Resources/Contacts.plist

有没有人知道为什么会发生这种情况?

【问题讨论】:

    标签: objective-c cocoa plist nsfilemanager


    【解决方案1】:

    您正在使用 stringByAppendingPathComponent: 方法设置文件路径。该方法返回一个自动释放的对象。 (Autoreleased 对象在(自动)释放后使用,这可能会导致错误的访问错误。)

    我想改变

    [rootPath stringByAppendingPathComponent:@"Contacts.plist"];
    

    进入

    [[rootPath stringByAppendingPathComponent:@"Contacts.plist"] retain];
    

    会解决你的烦恼。

    【讨论】:

    • 哇,这确实解决了我的问题,谢谢!你能告诉我更多关于问题所在吗?我很确定我从官方参考中复制了这一行。非常感谢!
    • 我推荐你看看这个教程:cocoadevcentral.com/d/learn_objectivec。它有一行说“对于本教程,您可以假设自动对象将在当前函数结束时消失。” (自动对象是自动释放的对象)。您在 awakeFromNib 函数之后设置的字符串“消失”,因此 filePath 变量引用了不再存在的内容,从而导致错误。保留它不会阻止它被自动发布,但会制作一个额外的副本,直到你告诉它才会发布。 (您可能应该在 -dealloc 中执行此操作。)
    • André Hoffmann:Apple 在 ADC 网站上有一个关于 Cocoa 内存管理的隐蔽但非常好的教程。 developer.apple.com/mac/library/documentation/General/…
    • 谢谢!我认为在 Obj-C 2.0 中,垃圾收集器会处理这个问题吗?还是还是好的做法?
    • 垃圾收集器确实会处理如果您使用垃圾收集。它是可选的,默认情况下是关闭的。而且它在 iPhone 上不存在,所以如果您希望代码(尤其是模型代码)在两个地方都运行,您需要将其编写为保留计数或双模式(为保留计数而编写和GC)。
    【解决方案2】:

    首先,我认为您不应该实例化 NSFileManager 对象。相反,您使用默认文件管理器,如下所示:

    [[NSFileManager defaultManager] fileExistsAtPath: filePath];
    

    那么,你能指定程序在哪一行进入调试器吗?

    【讨论】:

    • 我在哪里可以看到它在哪一行中断?它只显示汇编代码。感谢 fileManager 的提示..删除了实例化,但没有改变任何事情。
    • 如果您在 Cocoa 代码中崩溃,您将只能看到程序集。 Debugger 窗口的左侧是堆栈帧列表;选择你自己代码中的一个,你会看到你的源代码,相关的行以红色突出显示。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-25
    • 1970-01-01
    相关资源
    最近更新 更多