如何查找匹配对象:-[CFArray _cfTypeID]:发送到已释放实例的消息
Posted
技术标签:
【中文标题】如何查找匹配对象:-[CFArray _cfTypeID]:发送到已释放实例的消息【英文标题】:How to find matching object for: -[CFArray _cfTypeID]: message sent to deallocated instance 【发布时间】:2011-03-06 19:13:18 【问题描述】:我被这条错误消息卡住了,因为三天来我没有找到对象 _cfTypeID,也没有在该消息之后记录对象的地址。我知道一定有一个我可以访问的数组,但它已经被销毁了。
我的 iPhone 应用程序基于一个标签栏控制器,通过一个标签我切换到一个新的视图控制器,它创建一个导航视图控制器并隐藏整个标签栏控制器以防止被访问。我选择这种方式是因为整个标签栏视图逻辑以纵向运行,而导航视图控制器以横向运行。
当它通过标签栏从任何纵向视图开始时,第一次运行总是很好,然后更改为导航视图控制器的横向视图。我在导航堆栈上推送了三个视图。在第一次运行时,当我导航回根控制器时也没有崩溃,保持打开状态并返回标签栏控制器的最后一个可见视图。此时导航视图控制器将被释放。
崩溃发生在第二次运行时,再次从标签栏控制器导航到导航视图控制器,再到第三个推送视图控制器。此时导航视图控制器及其堆栈上的三个视图控制器被重新创建。当我通过按我创建为完成按钮的 backBarButton 或 rightBarButton 离开堆栈中最底部的视图时发生崩溃。
我还没有找到我对内存管理不满意的地方,因为我自己没有一个名为 _cfTypeID 的数组,也没有直接访问这个数组。 GDB 在调用 NSUserDefaults 同步期间崩溃,我在刚刚离开屏幕的视图的 viewWillDisappear 中使用该 NSUserDefaults。带有泄漏工具的仪器会在此崩溃后终止进程,并且它的消息对我没有帮助。
...在模拟器和设备(iPhone 4)上运行之间存在行为差异:在设备上,我可以从导航视图控制器中再弹出一个视图控制器,并在离开时崩溃backBarButton 的视图。
我决定不发布任何代码行,因为其中有很多代码行,将其放在这里可能没有意义。但如果需要,我可以提供其中的一部分。我很高兴能提供一些工具提示,我可以用来识别损坏的数组或其他任何东西来修改我的内存管理(这当然不是完美的,因为我对来自 c++ 和 php 的 objc 还很陌生)。
干杯, 康兰
【问题讨论】:
该错误肯定与您实现的数组有关,并且没有足够的保留。如果您实现了一个自动释放数组并且忘记了您以后需要它,这尤其常见。尝试使用调试器/工具来查找问题。 谢谢,但问题是我拥有的所有数组都没有名称 _cfTypeID ...我根本找不到该名称的任何引用。因此,到目前为止,所有调试器/仪器活动都失败了。我在创建后和销毁导航视图控制器之前使用地址和保留计数记录了所有视图控制器实例、数组和字典。一切看起来都不错(保留计数 2,导航视图控制器 3),除了第一个视图控制器使用 [self.theCtrl pushViewController:viewControl animated:NO]; 推送到堆栈上,其保留计数为 27和 2 在我销毁它之前。 【参考方案1】:_cfTypeId
不是数组的名称,它是发送到CFArray
实例的消息的名称。特定的错误来自框架代码内部的某个地方,这就是为什么你不认识它的原因,但原因是你的代码中的某些东西要么没有保留它应该保留的东西,要么释放了它不应该的东西,或者过早地发布它仍然想要使用的东西。
顺便说一句,不要使用retainCount
,它不像你想象的那样工作,而且通常没用。
【讨论】:
好吧,这给它增添了一些光彩……即使我还没有找到它。当我按下任何导航栏按钮时,它似乎确实在一个视图控制器中初始化崩溃。我在堆栈上移动了一些视图控制器并插入/附加了一个虚拟控制器,它总是与它死去的地方相同。我会继续研究... 谢谢,找到了。请参阅下面的代码,因为这里没有正确的格式。【参考方案2】:好的,很奇怪 - 但它是:
- (void)loadPrefs
NSUserDefaults* prefs = [NSUserDefaults standardUserDefaults];
NSMutableArray* tmpArr = nil;
// initialize currency name color array
if ((tmpArr = (NSMutableArray*)[diagView loadPrefsColorArray:@"diagCellColors"]) != nil)
self.cellColors = [NSMutableArray arrayWithArray:tmpArr];
else
self.cellColors = [diagView defaultCellColors];
tmpArr = nil; //+++ added this to release tmpArr
// initialize currency arrays
if ((tmpArr = [prefs objectForKey:@"diagUsedCurrencies"]) != nil)
self.arrCurrencies = [NSMutableArray arrayWithArray:tmpArr];
else
self.arrCurrencies = [NSMutableArray arrayWithCapacity:1];
tmpArr = nil; //+++ added this to release tmpArr
...
在我的原始代码中,我仅在从该方法返回之前将 tmpArr 设置为 nil。事实上,我不明白为什么有必要重置 tmpArr,因为我保留了我自己的引用(如 self.cellColors 是一个保留属性)。我几乎所有的视图控制器都有类似的结构,只有在一种情况下我遇到了这个未定义的崩溃。
【讨论】:
在那里分配 nil 实际上并没有释放任何东西。我猜想在某些时候 tmpArr 会保留其旧值,而不是分配给您认为应该的值。他们你释放它,不小心释放了那个旧值(这可能是已经自动释放的东西)。 谢谢阿诺米。无论如何,它碰巧意外释放旧值对我来说似乎很奇怪...... self.cellColors 由合成的 setter 方法调用,因此由其属性保留一次。我不明白为什么对 tmpArr 的第二次赋值(不将其值重置为 nil)可以释放旧值。唔。无论如何,我会像以前一样继续解决它。 代码中没有意外...多半是你刚刚转移了问题,它会在未来开始神秘地崩溃,只是会有更多的代码和更复杂的处理。您是否尝试使用 NSZombies 或其他工具来追踪此类问题? bbum,这听起来比预期的要糟糕。只要没有完成,我的项目中就有 NSZombieEnabled。由于静态分析器的输出以及 Instruments Leaks 工具和 GDB,我已经清理了代码。这里的事情发生在清理之后......当我得知 viewDidUnload 从未被调用过,所以没有任何东西被释放。我改变了一些东西,以便 dealloc 正确地删除我的数据变量 - 这样做我了解到我的许多数据变量和视图控制器保留了太多。现在他们没有正确释放。仅在第二次构建我的视图后才发生崩溃。以上是关于如何查找匹配对象:-[CFArray _cfTypeID]:发送到已释放实例的消息的主要内容,如果未能解决你的问题,请参考以下文章
从deque到std::stack,std::queue,再到iOS 中NSArray(CFArray)
如何使用find_if查找类的匹配对象? (或任何其他方式来实现结果)