gpt4 book ai didi

Cocoa 内存管理 - 对象在我身上为零

转载 作者:行者123 更新时间:2023-12-03 17:44:51 25 4
gpt4 key购买 nike

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

我有一个函数:

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

例如(为简洁起见,删除了错误处理)。

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;
}

调用函数在每个 session 中仅获取一次数组,并将其保留以供以后处理:

static NSMutableArray *gFolderPaths = nil;

...

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

现阶段一切看起来都很好。 [gFolderPaths count] 返回找到的正确路径数,[gFolderPaths description] 打印出所有正确的路径名称。

问题:

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

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

我的假设/假设

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

感谢任何帮助。

最佳答案

对象不会“go nil”。

static NSMutableArray *gFolderPaths = nil;

此声明声明 gFolderPaths 是一个保存指向 NSMutableArray 对象的指针的变量。您可以使用指向无对象的指针来初始化它:nil

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

When I go to use gFolderPaths later (say, the next run through my event loop) my assertion code (and gdb in Xcode) tells me that it is nil.

I am not modifying gFolderPaths in any way after that initial grab, so I am presuming that my memory management is screwed and that gFolderPaths is being released by the runtime.

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

因此,您可能会猜测您或某些其他代码(例如,在框架中)释放了您之前存储在 gFolderPaths 中的指针的对象。

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

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

事实并非如此。您说您的断言和对调试器的命令显示 gFolderPaths 变量包含 nil

有两种明显的可能性:

  1. 重新分配给变量的东西。你说你的代码没有重新分配给变量。其他人不应该知道它,所以这种可能性极小。
  2. 您从未将对象的指针分配给变量。要么您分配了nil,要么您从未分配过任何内容。您说您正在记录将其指针分配给变量的数组,并且说明已检查完毕,因此我们可以完全排除这种可能性。 (记录计数的测试不太可靠,因为 [nil count] 将成功返回 0。)

这导致了第三种可能性:

3. 您有两个 gFolderPaths 变量。

我猜您有两个函数或方法(或每个函数或方法之一)都包含此行:

static NSMutableArray *gFolderPaths = nil;

那是行不通的。两个 gFolderPaths 变量都是静态的,但对于您在其中声明它们的函数/方法来说也是本地的。每个函数/方法都有自己的 gFolderPaths 变量,因此您有两个这样的变量,彼此分开。

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

发生这种情况的另一种情况是,如果您有两个这样的全局声明,但每个声明都位于不同的文件中。在文件作用域声明的变量上的 static 意味着“仅在该文件内可见”,因此这会导致相同的问题:当您想要拥有一个共享变量时,会出现两个单独的变量。如果这是您的问题,立即的解决方法是从它们中删除 static 关键字,但如果您打算以这种方式使用全局变量,则应该重新考虑您的设计。

关于Cocoa 内存管理 - 对象在我身上为零,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3051426/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com