iphone - 由于 iPhone 应用程序中的 "message sent to deallocated instance"导致崩溃不一致

标签 iphone objective-c cocoa cocoa-touch

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

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

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

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

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

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

如果我可以提供任何有帮助的其他信息,请告诉我。

提前致谢!抱歉,如果我太长太彻底(INTP)!

-罗本

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

崩溃位置#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

示例回溯(这对应于第 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 的教程显示了输出,它们都像“它就在那里”,而我则想“在哪里?你在看什么”):

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

最佳答案

需要注意的几件事:

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

[_foo release], _foo = nil;

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

如果您有 10.6,那么我强烈推荐静态分析器。按 Cmd-Shift-A,它会查找明显的内存错误。我发现它非常擅长。

关于iphone - 由于 iPhone 应用程序中的 "message sent to deallocated instance"导致崩溃不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2367739/

相关文章:

iphone - 在处理核心数据时如何停止内存的积累?

ios - 如何以编程方式获取正确的 iOS 版本?

iphone - 谁能告诉我IOS中调用的区别

iphone - 在 UIScrollView 上平滑移动元素

iphone - IFTweetLabel 长 URL 的主要问题

ios - 如何在两个 UIAlertView 之间做事(ios7)

java - 使用 C++ 中的库为 PhoneGap 创建插件

xcode - 构建应用程序,使其可以在不同版本的 OS X 上运行

swift - 在 Swift 中制作 NSWindowController Singleton 的正确方法是什么?

objective-c - 在通过谓词获取 NSArray 后,如何获取其父 NSMutableArray 中的 NSArray 索引