测试对象是否已取消分配

时间:2010-06-23 12:52:42

标签: iphone objective-c

我有一种情况,偶尔我的-tableView: numberOfRowsInSection:方法要求取消分配NSArray的计数。我希望能够测试这个数组是否以一种安全的方式解除分配,并且不会调用僵尸。

我的代码目前看起来像:

-(NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section
{
    if (! self.offers){
        return 0;
    }
    return [self.offers count];
}

我只是通过调试程序逐步执行此操作并观察它通过! self.offers测试,然后在[self.offers count]上残酷地崩溃。我打开了NSZombies,在那行我得到了NSLog消息:

-[__NSArrayM count]: message sent to deallocated instance 0x283dc0

因此,无论自我提供什么,在这一点上,不是零,但也没有指出任何有效的东西。我该如何测试?

编辑:感谢强烈的爱,朋友们。我已经弄清楚为什么我的内存管理遇到了麻烦 - 这实际上是委托关系的问题比它们有用的时间更长。在这里查看我的问题的完整答案: Managing calls to objects that get deallocated when the view is backed out of

6 个答案:

答案 0 :(得分:15)

这是不可能“测试”的 - 一旦一个对象被释放,它就消失了,指向它的指针实际上是垃圾。对它做任何事情都可能会崩溃。

很抱歉成为坏消息的持有者,但让这项工作正常运行的唯一方法是确保内存管理(在这种情况下)offers在所有用途中都是正确的 - 保留和释放正确操作该实例变量的所有点,它永远不会是非零垃圾。

您应该尝试运行静态分析器(Build-> Build and Analyze)来开始 - 这个工具可以帮助标记内存管理模式问题,而无需您进行大量的额外挖掘。

答案 1 :(得分:1)

你应该通过修复代码来避免这个问题,这样当它显然仍然需要时它不会释放数组。

答案 2 :(得分:1)

您可以添加

-(void)dealloc { ... }

如果是正确的话,请将其留空,并在其中添加断点。

此答案更正为ARCNON-ARC

答案 3 :(得分:0)

这可能与您的问题无关(测试是否已取消分配) - 但您的商品数组似乎与您的UITableViewController具有相同或更长的生命周期,您确定吗?你保留了这个数组,或者你不小心将它放在其他地方。

答案 4 :(得分:0)

我同意quixoto上面所说的内容。

您必须要问自己的另一件事是,我的应用程序设计正确吗? tableview依赖于一个数据源来填充它(在你的情况下是offers数组),所以如果你在代码中的某个地方解除分配,那么你需要退后一步并重新考虑你的设计。

如果您正在测试它是否因为您尝试从之前的问题“修复”它而被解除分配,那么可能值得查看您的代码以查看其保留/释放的位置。

答案 5 :(得分:0)

是的,一旦一个对象被释放,它就消失了,指向它的指针实际上是垃圾。对它做任何事情都可能会崩溃。

然而,测试是可能的。有一个解决方法。 (虽然解决方法不能替代良好的设计实践!): 您有一个全局BOOL变量,您可以在alloc上设置该变量。这是用于检查AVAudioPlayer是否正在播放的示例。如果它正在播放,并且视图已关闭,则应用程序将崩溃。由于后台线程等原因,暂停音乐不是一个选项。但是当newPlayer已经发布时,调用[newPlayer isPlaying]会崩溃!所以BOOL标志的解决方法使它工作。 (对此有任何好的设计实践评论都很有价值。)

// In implementation
static AVAudioPlayer *newPlayer;
static BOOL hasMusicFinishedPlaying;

// When Playing the music, set flag
    newPlayer =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath: soundPath] error:nil];    
    hasMusicFinishedPlaying = NO;

// Callback method to release new player in playKeySound
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)newPlayer successfully:(BOOL)flag {

    [newPlayer release];
    hasMusicFinishedPlaying = YES;
}

// On going back to another page. We don't want to keep ViewController in stack.

    if (!hasMusicFinishedPlaying){
        return;
    }

    [self.navigationController popViewControllerAnimated:YES];