可可内存管理 - 对象对我不利

时间:2010-06-16 07:37:28

标签: cocoa memory-management

Mac OS X 10.6,Cocoa项目,带保留/释放gc

我有一个功能:

  • 遍历特定目录,扫描子文件夹(包括嵌套文件夹),构建NSMutableArray字符串(每个找到的子文件夹路径一个字符串),然后返回该数组。

e.g。 (为简洁起见,删除了错误处理)。

NSMutableArray * ListAllSubFoldersForFolderPath(NSString *folderPath)
{
    NSMutableArray *a = [NSMutableArray arrayWithCapacity:100];
    NSString *itemName = nil;
    NSFileManager *fm = [NSFileManager defaultManager];
    NSDirectoryEnumerator *e = [fm enumeratorAtPath:folderPath];

    while (itemName = [e nextObject]) {
        NSString *fullPath = [folderPath stringByAppendingPathComponent:itemName];
        BOOL isDirectory;
        if ([fm fileExistsAtPath:fullPath isDirectory:&isDirectory]) {
            if (isDirectory is_eq YES) {
                [a addObject: fullPath];
            }
        }           
    }
    return a;
}

调用函数每个会话只接受一次数组,保留它以供以后处理:

static NSMutableArray *gFolderPaths = nil;

...

gFolderPaths = ListAllSubFoldersForFolderPath(myPath);
[gFolderPaths retain];

在这个阶段,所有人都表现得很好。 [gFolderPaths count ]返回找到的正确路径数,[ gFolderPaths description] 打印出所有正确的路径名。

问题:

当我稍后使用 gFolderPaths 时(比如,下一次运行我的事件循环),我的断言代码(以及Xcode中的gdb)告诉我它是零。

我没有在初始抓取之后以任何方式修改 gFolderPaths ,所以我假设我的内存管理被搞砸了并且运行时正在发布gFolderPaths。

我的假设/推定

我没有保留每个字符串,因为我将它添加到可变数组中,因为这是自动完成的,但是我必须保留数组,一旦它从函数移交给我,因为我不会立即使用它。这是对的吗?

感谢任何帮助。

1 个答案:

答案 0 :(得分:2)

对象不“去nil”。

static NSMutableArray *gFolderPaths = nil;

此声明声明gFolderPaths是一个包含指向NSMutableArray对象的指针的变量。 使用指向无对象的指针初始化它:nil

这个初始化是有效的,并且有意义,因为你没有一个数组可以放在这里 - 更好地使用nil指针初始化而不是初始化并冒一些随机指针在变量中。 (static变量不会发生这种情况,因为static变量无论如何都被初始化为nil,但显式性很好而且显式初始化是无害的。)

  

当我稍后使用gFolderPaths时(比如,下一次运行我的事件循环)我的断言代码(以及Xcode中的gdb)告诉我它是nil

     

在初始抓取之后,我没有以任何方式修改gFolderPaths,因此我假设我的内存管理被搞砸了,并且运行时正在释放gFolderPaths

没有。运行时不释放对象。运行时是语言的一部分,retainrelease是Foundation框架的一部分。该框架位于语言之上。

所以,你可能会猜到你或其他一些代码(例如,在框架中)发布了你之前存储在gFolderPaths中的指针的对象。

没有。如果发生这种情况,gFolderPaths变量不会突然包含nil;它仍然包含指向同一对象的相同指针。如果这是对象死亡之前的最后一个版本,那么gFolderPaths变量仍将包含指向相同的,现在已死的对象的相同指针。

尝试记录指针(例如,使用NSLog(@"%p", gFolderPaths))将打印一个看似有效的地址,例如0x2381ab6780。尝试记录对象(例如,使用%@)几乎肯定会崩溃,因为对象已经死了。

那不是发生了什么事。你说你的断言和你对调试器的命令显示gFolderPaths变量包含nil

有两个明显的可能性:

  1. 重新分配给变量的内容。您说没有您的代码重新分配给变量。没有其他人应该知道它,所以这种可能性极不可能。
  2. 您从未在第一时间分配对象指向变量的指针。您指定了nil,或者您从未指定任何内容。你说你正在记录你指定给变量的指针的数组,并且说明检查了,所以我们可以完全忽略这种可能性。 (记录计数的测试不会那么可靠,因为[nil count]将成功返回0。)
  3. 这导致了第三种可能性:

    3。 您有两个gFolderPaths个变量。

    我猜你有两个函数或方法(或其中一个)都包含这一行:

    static NSMutableArray *gFolderPaths = nil;
    

    那不行。两个gFolderPaths变量都是静态的,但也是你声明它们的函数/方法的局部变量。每个函数/方法都有自己的gFolderPaths变量,所以你有两个这样的变量,彼此分开。 / p>

    您需要在任何函数或方法之外将gFolderPaths声明为静态全局变量。更好的是,如果仅从实例访问它,则将其设为实例变量。无论哪种方式,如果您想在两个函数或方法之间共享它,它就不能是局部变量。

    另一种可能发生的方式是,如果您有两个这样的全局声明,但每个声明都在不同的文件中。 static在文件范围内声明的变量意味着“仅在此文件中可见”,因此这会导致同样的问题:当您想拥有一个共享变量时,需要两个单独的变量。如果这是您的问题,立即修复是从这两个关键字中删除static关键字,但如果您打算以这种方式使用全局变量,则应重新考虑您的设计。