NSZombie - 保留/释放调用应该由库配对吗?

Posted

技术标签:

【中文标题】NSZombie - 保留/释放调用应该由库配对吗?【英文标题】:NSZombie - should retain/release calls be paired by library? 【发布时间】:2013-09-23 10:48:27 【问题描述】:

TL:DR 版本:我使用 NSZombieEnabled 来查找 EXC_BAD_ACCESS 错误的来源,并看到一个库的版本比保留的多 1 个。我可以假设这个库导致了崩溃,还是该版本与来自另一个库的保留相关联?

我在我的应用程序中遇到一些问题,UITableViewCell 子类实例在其保留计数达到 0 后收到消息。我使用 NSZombies 运行该应用程序,目前正在尝试配对保留/释放调用以查找错误的确切来源从。我注意到只有 2 个保留和 3 个版本将“责任库”设置为 QuartzCore。这是否意味着额外的发布调用是导致我的应用程序崩溃的原因?还是有可能某个版本在另一个库中关联了保留?

附加信息: My section headers are tappable, when one is selected, the row for this section is inserted into table view and any previously visible row is deleted.换句话说,一次只能有 1 个部分有 1 行,所有其他部分必须有 0 行。

我配对的来自 QuartzCore 的释放/保留调用是:

CALayer layoutSublayers    (retains)
CA::Layer::layout_if_needed(CA::Transaction*)    (releases)

没有配对的版本是:

CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*)

我遇到崩溃的确切行是 endUpdates 行:

- (void)sectionHeaderView:(SectionHeaderView *)sectionHeaderView sectionOpened:(NSInteger)sectionOpened 

    SectionInfo *sectionInfo = [self.sectionInfoArray objectAtIndex:sectionOpened];

    sectionInfo.open = YES;

    NSMutableArray *indexPathsToInsert = [[NSMutableArray alloc] init];

    [indexPathsToInsert addObject:[NSIndexPath indexPathForRow:0 inSection:sectionOpened]];


    /*
     Create an array containing the index paths of the rows to delete: These correspond to the rows for each quotation in the previously-open section, if there was one.
     */
    NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];

    NSInteger previousOpenSectionIndex = self.openSectionIndex;
    if (previousOpenSectionIndex != NSNotFound) 

        SectionInfo *previousOpenSection = [self.sectionInfoArray objectAtIndex:previousOpenSectionIndex];
        previousOpenSection.open = NO;
        previousOpenSection.category.model = nil;
        [previousOpenSection.headerView toggleOpenWithUserAction:NO];

        [indexPathsToDelete addObject:[NSIndexPath indexPathForRow:0 inSection:previousOpenSectionIndex]];

    


    // Style the animation so that there's a smooth flow in either direction.
    UITableViewRowAnimation insertAnimation;
    UITableViewRowAnimation deleteAnimation;
    if (previousOpenSectionIndex == NSNotFound || sectionOpened < previousOpenSectionIndex) 
        insertAnimation = UITableViewRowAnimationTop;
        deleteAnimation = UITableViewRowAnimationBottom;
    
    else 
        insertAnimation = UITableViewRowAnimationBottom;
        deleteAnimation = UITableViewRowAnimationTop;
    

    NSIndexPath *indexToDelete = [indexPathsToDelete firstObject], *indexToInsert = [indexPathsToInsert firstObject];
    if (indexToDelete == nil) 
        NSLog(@"no row to delete");
    
    else 
        NSLog(@"deleting row %d section %d", [indexToDelete row], [indexToDelete section]);
    
    NSLog(@"inserting row %d section %d", [indexToInsert row], [indexToInsert section]);

    // Apply the updates.
    [self.tableView beginUpdates];
    [self.tableView insertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:insertAnimation];
    [self.tableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:deleteAnimation];
    [self.tableView endUpdates];  // this is the crash.

    self.openSectionIndex = sectionOpened;


    [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:sectionOpened] atScrollPosition:UITableViewScrollPositionNone animated:YES];


错误发生在 ios7 上。

【问题讨论】:

启用zombie后,你在你的项目中找到Zombie了吗? 是的,这是我的 UITableViewCell 子类实例 所以不要在你得到僵尸的地方释放你的对象,因为这个对象正在你的代码中使用,如果你在那里释放它,那么你正在使用一个已经被释放的对象并且这就是为什么僵尸在那里被养的原因。 你的问题解决了吗? @johnyu 好问题,你有崩溃的回溯吗? 【参考方案1】:

如果数组中的索引路径无效(例如,-1 的节号),您可以在 endUpdates 行获得 EXC_BAD_ACCESS。您应该 NSLog 您的 indexPathsToInsertindexPathsToDelete 并确保它们包含有效值。

【讨论】:

我已经这样做了,但一切似乎都很好。而且我认为使用无效的 indexPath 我会收到一条错误消息,但我没有。 @johnyu 有时无效的NSIndexPath 值会在endUpdates 处精确生成EXC_BAD_ACCESS(这是我可以重现该异常的唯一方法),这就是我建议它的原因。但是,如果您确信传递给 insertRowsAtIndexPathsdeleteRowsAtIndexPaths 的值是有效的,那么一定不是这样。祝你好运。【参考方案2】:

我已经找到了解决这个问题的方法。似乎在异步请求结束后,表格单元格的子视图之一正在调用 becomeFirstResponder。当然,如果牢房在那一刻已经被释放,那么崩溃就发生了。起初我只是假设问题是由于保留和释放的不平衡,但看起来不是这样。

并回答标题中的问题:当与 NSZombieEnabled Instruments 一起运行时,应用程序已经配对了一些保留/释放,当它可以假设它们已连接时。在我的应用程序的一次运行中,Instruments 加入了来自 QuartzCore 的发布与来自 UIKit 的保留。尽管我不能 100% 确定它是正确的,但我认为“责任库”标签相同不是强制性的。

TL:DR - 我很确定保留可以与来自另一个库的发布配对。

【讨论】:

以上是关于NSZombie - 保留/释放调用应该由库配对吗?的主要内容,如果未能解决你的问题,请参考以下文章

这个变量应该手动释放吗?

对象被释放但没有调用 dealloc

NSZombie 分配日志不一致

我应该总是为失败的初始化方法释放自我吗?

当 self 被释放时我应该调用完成处理程序吗

iOS 9 的点播资源可以永久保留吗?