NSFileManager 和 NSDirectoryEnumerator 崩溃?

Posted

技术标签:

【中文标题】NSFileManager 和 NSDirectoryEnumerator 崩溃?【英文标题】:NSFileManager and NSDirectoryEnumerator Crash? 【发布时间】:2011-03-09 21:24:04 【问题描述】:

下面的代码在walker = [fileManager enumeratorAtPath:directory]; 崩溃。代码在第一次调用 refresh 时执行正常,但在第二次(和后续)调用时崩溃。

关于我可能做错了什么有什么想法吗?

- (void)refresh

    NSString* directory = nil;
    NSFileManager* fileManager = nil;
    NSDirectoryEnumerator* walker = nil;

    if(files == nil)
        files = [[NSMutableArray alloc] init];
    else
        [files removeAllObjects];

    ASSERT(files != nil);
    if(files == nil) goto EARLY_EXIT;

    fileManager = [[NSFileManager alloc] init];
    ASSERT(fileManager != nil);
    if(fileManager == nil) goto EARLY_EXIT;

    directory = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
    ASSERT(directory != nil);
    if(directory == nil) goto EARLY_EXIT;

    ASSERT(directory != nil);
    walker = [fileManager enumeratorAtPath:directory];
    ASSERT(walker != nil);
    if(walker == nil) goto EARLY_EXIT;

    NSString* file;
    while((file = [walker nextObject]) != nil)
           
        BOOL isDirectory = YES;
        if([fileManager fileExistsAtPath:file isDirectory:&isDirectory] && !isDirectory)
            [files addObject:file];
    

EARLY_EXIT:

    //if(walker != nil)
    //  [walker release];

    if(fileManager != nil)
        [fileManager release];

    //if(directory != nil)
    //  [directory release];

【问题讨论】:

请,请,请不要使用 goto! (说真的……阅读一下这个!) 不敢相信,25 年后,我再次面临 goto 的邪恶!见鬼,我什至不知道你可以在 Objective-C 中做到这一点。虽然,它确实解释了当我在 Apple 工作时,他们在火刑柱上烧死了一个人。 > 25 年后我不敢相信我再次面临 goto 的邪恶。我在 30 多年前就学会了——旧习惯很难改掉。 你看到什么样的崩溃?您是否已验证 NSHomeDirectory() 每次都返回您期望的结果? 【参考方案1】:

事实证明,在 ios 和 10.5 及更高版本中,您不应再使用[NSFileManager defaultManager]。使用 Cocoa 近 15 年,我在这个问题上咬了一口。我会把它留给其他人的警告 -- TechZen

尽管您在这段代码中犯下了许多违背良好编程习惯的罪过,但您真正的问题在这里:

fileManager = [[NSFileManager alloc] init];

NSFileManger 在每个应用程序中都是一个单例。你永远不会自己初始化它。获取单例的正确方法是:

fileManager=[NSFileManager defaultManager];

... 返回单例。但是,您通常不会为属性或变量而烦恼,而只是这样使用它:

walker = [[NSFileManager defaultManager] enumeratorAtPath:directory];

你知道你不应该在发布代码中使用断言,对吧?

【讨论】:

> 尽管有许多不利于良好编程实践的罪过。我会认为你也不关心 goto 的。就个人而言,我真的不关心样式,只要所有返回值都被断言和检查。 > NSFileManger 在每个应用程序中都是一个单例。您永远不会自己初始化 > 它。获取单例的正确方法是: > fileManager=[NSFileManager defaultManager];嗯...我读过的 Apple 文档指出 defaultManager 不是线程安全的,应该使用 [[NSFileManager alloc] init] @noloader -- 哈!你说得对,文档现在说不要在 iOS 和 10.5 及更高版本中使用 [NSFileManager defaultManager]。我被旧知识烧伤了。看来你不是唯一一个有旧习惯的人。现在,我必须回去修复一些代码,很多代码。 @noloader -- *** 不允许 cmets 中的段落格式。只是粗体、斜体、代码和链接(都是内联的。)【参考方案2】:

我发现了同样的崩溃。在 iOS 4.3 中崩溃,但在 5.0 中运行良好。哈哈。我通过代码重构以使用字符串枚举器而不是 url 枚举器:

    NSFileManager* localFileManager = [[NSFileManager alloc] init];
    NSDirectoryEnumerator* enumerator = [localFileManager enumeratorAtPath:path];
    for (NSString* file in enumerator) 
        // do stuff...
    

祝你好运。 (并摆脱那些 goto)。

【讨论】:

以上是关于NSFileManager 和 NSDirectoryEnumerator 崩溃?的主要内容,如果未能解决你的问题,请参考以下文章

NSFileManager - 创建一个只读文件

NSFileManager 不保存数据

NSFileManager 线程安全

NSFileManager:无法正常工作

为啥 NSFileManager 找不到这些 png 文件?

NSFileManager 从服务器读取文件?