由于iPhone App中“发送到解除分配的实例的消息”导致的崩溃不一致

时间:2010-03-02 23:32:36

标签: iphone objective-c cocoa cocoa-touch

最初,我的应用程序崩溃了BAD_EXEC_ACCESS。我打开了NSZombieEnabled,输出如下。崩溃是非常不一致的,如果它崩溃,它总是在三个地方之一崩溃,但它在经过那些代码行时并不总是崩溃。即有时它会在前10个用户交互中的其中一个地方崩溃,有时候我可以持续按下控件(通过这些代码行)超过一分钟,然后它最终崩溃。

NSZombieEnabled的输出也不一致,如“崩溃位置#2”中所述 - 两个NSZombieEnabled输出是应用程序在同一行代码上崩溃但具有不同NSZombieEnabled输出的示例。

我知道通常这种类型的错误意味着我过度释放某些东西,但我不能弄清楚我做错了什么。

我遵循的内存管理规则是:

  1. 对于每个init / alloc我都有相应的版本 (在我的代码中,没有任何一点比在方法中创建的对象更复杂,然后在同一方法中稍后发布。)
  2. 对于保留的每个属性,我在dealloc()
  3. 中都有相应的版本

    (我听说“将IBOutlets设置为nil”与内存管理有关,但我没有找到关于如何完成此操作的充分描述,因此我的应用程序中没有这样做。)

    如果我能提供任何有用的其他信息,请告诉我。

    提前致谢!对不起,如果我太长而且彻底(INTP)!

    -Roben

    以下是崩溃输出的一些记录。发生崩溃时,它始终位于这三个位置之一。通过在崩溃后进行回溯并查找我编写的行号和代码文件来确定位置。

    崩溃位置#1:

    if (![[self fetchedResultsController] performFetch:&error])
    

    示例崩溃位置#1 NSZombieEnabled输出:

    *** -[Not A Type release]: message sent to deallocated instance 0x3b3f570
    

    崩溃地点#2:

    NSMutableArray *tips = [NSMutableArray arrayWithArray: [[[categories objectAtIndex: indexPath.row] valueForKey:@"tips"] allObjects]];
    

    示例崩溃位置#2 NSZombieEnabled输出:

    *** -[CFArray retain]: message sent to deallocated instance 0x3e53990
    *** -[NSFetchRequest retain]: message sent to deallocated instance 0x3b2f2c0
    

    崩溃地点#3:

    NSMutableArray *tips = [NSMutableArray arrayWithArray: [[[justOneCategory objectAtIndex: 0] valueForKey:@"tips"] allObjects]];
    

    示例崩溃位置#3 NSZombieEnabled输出:

    *** -[UIViewControllerWrapperView retain]: message sent to deallocated instance 0x3e593a0
    

    示例Backtrace(这对应于第3行):

    #0  0x01d6a3a7 in ___forwarding___ ()
    #1  0x01d466c2 in __forwarding_prep_0___ ()
    #2  0x01cfd988 in CFRetain ()
    #3  0x01cfd495 in CFArrayCreate ()
    #4  0x01d406c3 in -[__NSPlaceholderArray initWithObjects:count:] ()
    #5  0x01d5d34a in +[NSArray arrayWithObjects:count:] ()
    #6  0x01d6386e in -[NSSet allObjects] ()
    #7  0x00003bbc in -[RootViewController getRandomTip:] (self=0x3b24ea0, _cmd=0x7447, sender=0x3b38330) at /Users/***/Classes/RootViewController.m:36
    #8  0x00299405 in -[UIApplication sendAction:to:from:forEvent:] ()
    #9  0x002fcb4e in -[UIControl sendAction:to:forEvent:] ()
    #10 0x002fed6f in -[UIControl(Internal) _sendActionsForEvents:withEvent:] ()
    #11 0x002fdabb in -[UIControl touchesEnded:withEvent:] ()
    #12 0x002b2ddf in -[UIWindow _sendTouchesForEvent:] ()
    #13 0x0029c7c8 in -[UIApplication sendEvent:] ()
    #14 0x002a3061 in _UIApplicationHandleEvent ()
    #15 0x0252ed59 in PurpleEventCallback ()
    #16 0x01d41b80 in CFRunLoopRunSpecific ()
    #17 0x01d40c48 in CFRunLoopRunInMode ()
    #18 0x0252d615 in GSEventRunModal ()
    #19 0x0252d6da in GSEventRun ()
    #20 0x002a3faf in UIApplicationMain ()
    #21 0x00002a60 in main (argc=1, argv=0xbfffef9c) at /Users/***/main.m:14
    

    编辑:添加Griffo要求的其他一些代码和输出

    感谢您的回复,更多具体的代码可以提供哪些帮助?现在,这里包含崩溃位置#1和崩溃位置#2的整个方法。

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    
        if (indexPath.section == ALLTIPS_SECTION) {
    
            self.tipsController.title = @"Tips";
    
            NSError *error = nil;
            if (![[self fetchedResultsController] performFetch:&error]) {
    //          NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    //          abort();
            }
            self.tipsController.tips = [NSArray arrayWithArray: [fetchedResultsController fetchedObjects]];
    
        } else {        
    
            self.tipsController.title = [[categories objectAtIndex: indexPath.row] name];
    
            NSMutableArray *tips = [NSMutableArray arrayWithArray: [[[categories objectAtIndex: indexPath.row] valueForKey:@"tips"] allObjects]];
    
            NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending: YES];
            [tips sortUsingDescriptors: [NSArray arrayWithObject: sortDescriptor]];
            [sortDescriptor release];
    
            self.tipsController.tips = [NSArray arrayWithArray: tips];
        }
        [self.navigationController pushViewController:self.tipsController animated:YES];
    }
    

    我没有针对您询问的具体崩溃运行malloc_history,但是我确实在#3上运行了它,这里输出,我不知道我应该如何解析这个,所以任何建议都会有所帮助(在所有关于malloc_history的教程我已经阅读了它们显示的输出,它们都像“它就在那里”而我就像“在哪里?wtf你在看”:)

    ALLOC 0x3b55130-0x3b5516f [size=64]: thread_a0a3f500 |start | main | UIApplicationMain | GSEventRun | GSEventRunModal | CFRunLoopRunInMode | CFRunLoopRunSpecific | PurpleEventCallback | _UIApplicationHandleEvent | -[UIApplication sendEvent:] | -[UIWindow _sendTouchesForEvent:] | -[UIControl touchesEnded:withEvent:] | -[UIControl(Internal) _sendActionsForEvents:withEvent:] | -[UIControl sendAction:to:forEvent:] | -[UIApplication sendAction:to:from:forEvent:] | -[RootViewController getRandomTip:] | -[_NSFaultingMutableSet allObjects] | -[_NSFaultingMutableSet willRead] | -[NSManagedObjectContext(_NSInternalAdditions) _retainedObjectWithID:optionalHandler:withInlineStorage:] | +[NSManagedObject(_PFDynamicAccessorsAndPropertySupport) allocWithEntity:] | _PFAllocateObject | malloc_zone_calloc 
    ----
    FREE  0x3b55130-0x3b5516f [size=64]: thread_a0a3f500 |start | main | UIApplicationMain | GSEventRun | GSEventRunModal | CFRunLoopRunInMode | CFRunLoopRunSpecific | __CFRunLoopDoObservers | _performRunLoopAction | -[_PFManagedObjectReferenceQueue _processReferenceQueue:] | _PFDeallocateObject | malloc_zone_free 
    
    ALLOC 0x3b55130-0x3b55153 [size=36]: thread_a0a3f500 |start | main | UIApplicationMain | GSEventRun | GSEventRunModal | CFRunLoopRunInMode | CFRunLoopRunSpecific | __CFRunLoopDoObservers | CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) | CA::Transaction::commit() | CA::Context::commit_transaction(CA::Transaction*) | CALayerLayoutIfNeeded | -[CALayer layoutSublayers] | -[UILayoutContainerView layoutSubviews] | -[UINavigationController _startDeferredTransitionIfNeeded] | -[UINavigationController _startTransition:fromViewController:toViewController:] | +[UIViewControllerWrapperView wrapperViewForView:frame:] | +[NSObject alloc] | +[NSObject allocWithZone:] | _internal_class_createInstance | _internal_class_createInstanceFromZone | calloc | malloc_zone_calloc
    

4 个答案:

答案 0 :(得分:3)

有几点需要注意:

首先,关于“设置为零”,这是一个很好的做法。无论何时释放某些东西,立即将其设置为零。这意味着-dealloc通常看起来像这样(或者其他十几种带有分号,两行等的样式):

[_foo release], _foo = nil;

但我怀疑这是你的问题。在您发送的malloc_history中,它显示有问题的对象是NSManagedObject,因此它是Core Data之外的东西。确保您已阅读Memory Management Using Core Data文档。

如果您有10.6,那么我强烈推荐使用静态分析仪。点击Cmd-Shift-A,它会寻找明显的内存错误。我发现它非常好。

答案 1 :(得分:0)

可能是由于您自动释放后来引用的对象,这可能解释了不一致性

“非类型”发布错误可能取决于您在代码中发布未定义为“某事”的内容。您是否为“非类型”错误引用的解除分配的实例运行“shell malloc history”命令?

需要真正看到更多代码...

答案 2 :(得分:0)

这就是发生崩溃的地方,但这并不意味着它就是bug的所在。发生崩溃是因为释放的对象正在发送消息,但该错误可能是当您仍想使用该对象时首先取消分配该对象的事实。我有一种模糊的感觉,最初取消分配的对象可能是tipsControllerfetchedResultsController,而且它也会发布其他内容。

答案 3 :(得分:0)

我有这个错误。我复制并粘贴了另一个应用程序的代码,其工作方式略有不同。就我而言,我在viewDidUnload&中释放变量。 viewWillDisappear。我注释掉了viewWillDisappear版本,将这些版本留在viewDidUnload中,并且应用程序工作正常而不会崩溃。希望这有助于其他人。