最终更新:结果证明这个问题的解决方法令人沮丧。进入项目中的 .xcodeproj 目录,然后删除<username>.mode1v3
和 <username>.pbxuser
文件。那解决了它。嘘,Xcode。
我将首先说这不是您通常的保留/释放错误。它刚刚开始在我的代码的开发分支上发生,主分支上不存在该错误,而且我无法找到指向答案的源代码中的任何差异。因此,我将直接讨论血腥的东西。
我有一个视图控制器类。它有几个属性引用了其他几个视图控制器。每个都根据需要通过 getter 访问器加载,如下所示:
- (NotesViewController *)notesViewController {
if (notesViewController == nil) {
notesViewController = [[NotesViewController alloc] initWithNibName:@"NotesViewController" bundle:nil];
}
return notesViewController;
}
当您稍后接听电话[self notesViewController]
时,一切都很好。然而,这个刚刚停止工作:
- (DateFieldController *)dateFieldController {
NSLog(@"made it into the method at least ...");
if (dateFieldController == nil) {
NSLog(@"nib loader, don't let us down...");
dateFieldController = [[DateFieldController alloc] initWithNibName:@"DateFieldController" bundle:nil];
}
return dateFieldController;
}
当此方法以与其他访问器相同的方式被调用时,它会爆炸,显然是在 nib 加载期间,但可能在它之前:
2010-07-08 11:44:58.029 MyApp[24404:207] made it into the method at least ...
2010-07-08 11:44:58.030 MyApp[24404:207] nib loader, don't let us down...
Program received signal: “EXC_BAD_ACCESS”.
(gdb) bt
#0 0x028bb0ca in _class_isInitialized ()
#1 0x028b9eca in _class_initialize ()
#2 0x028bf1f6 in prepareForMethodLookup ()
#3 0x028b86c9 in lookUpMethod ()
#4 0x028b8836 in _class_lookupMethodAndLoadCache ()
#5 0x028c6ad3 in objc_msgSend ()
#6 0x00007bb3 in -[EntryViewController controllerForFieldType:] (self=0x7942d70, _cmd=0x190c20, type=0x79844b0) at /Users/wgray/Documents/Sources/iPhone/MyApp-iphone/Classes/EntryViewController.m:481
#7 0x00007e07 in -[EntryViewController selectTypesControllerDidSelect:] (self=0x7942d70, _cmd=0x190bb4, type=0x79844b0) at /Users/wgray/Documents/Sources/iPhone/MyApp-iphone/Classes/EntryViewController.m:527
#8 0x0000d2ad in -[TypesViewController tableView:didSelectRowAtIndexPath:] (self=0x5d2aac0, _cmd=0x1eac458, aTableView=0x6056000, indexPath=0x781c780) at /Users/wgray/Documents/Sources/iPhone/MyApp-iphone/Classes/TypesViewController.m:81
#9 0x0059e718 in -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] ()
#10 0x00594ffe in -[UITableView _userSelectRowAtIndexPath:] ()
#11 0x002abcea in __NSFireDelayedPerform ()
#12 0x0274cd43 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ ()
#13 0x0274e384 in __CFRunLoopDoTimer ()
#14 0x026aad09 in __CFRunLoopRun ()
#15 0x026aa280 in CFRunLoopRunSpecific ()
#16 0x026aa1a1 in CFRunLoopRunInMode ()
#17 0x02fd02c8 in GSEventRunModal ()
#18 0x02fd038d in GSEventRun ()
#19 0x0053ab58 in UIApplicationMain ()
#20 0x00001e24 in main (argc=1, argv=0xbffff050) at /Users/wgray/Documents/Sources/iPhone/MyApp-iphone/main.m:14
(gdb)
触发 nib load 方法时,Simulator SDK 中似乎发生了一些令人讨厌的事情。事实上,可能更早。在 NSLog 中使用一点 NSLog 操作覆盖 nib 加载初始化程序DateFieldController
让我们毫无疑问地无处可去:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
NSLog(@"come on, you...");
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]))
{
NSLog(@"rock on!");
}
return self;
}
可以说,这些 NSLog 语句都没有被执行过。
发生什么了?为什么运行时对我喋喋不休?(将调用从 切换self.dateFieldController
到[self dateFieldController]
并不能修复错误——请记住,这段代码与我的主分支上的代码完全相同,它没有崩溃)。
FWIW,我正在使用 XCode 3.2.3 64 位构建,为 Simulator 4.0 编译,调试,i386 arch(在运行 OS X 10.6.3 的新 Mac Book Pro 上),项目设置中的部署目标设置为“iPhone OS 3.0"(将其升级到 3.1.3 也不能修复它)。
更新:根据要求,实施controllerForFieldType:
:
- (id)controllerForFieldType:(Type *)type {
id controller = nil;
if ([type.mode isEqualToString:@"note"]) {
controller = self.notesViewController;
} else if ([type.mode isEqualToString:@"date"]) {
NSLog(@"going for it, attempting to load dateFieldController from accessor...");
controller = self.dateFieldController;
} else {
controller = self.fieldViewController;
}
return controller;
}
我之前忽略了这个,因为我认为它不是特别相关,问题似乎发生在堆栈的后面,在实际的 getter 方法dateFieldController
中。
更新二:在@zneak 的建议下,我打开了设置 Run -> Enable Guard Malloc 并再次运行该场景。结果基本一样,只是运行时内部的回溯不一样。阻止它被解码的类或 NIB 似乎有问题:
2010-07-08 12:26:26.180 Strip[24961:207] made it into the method at least ...
2010-07-08 12:26:26.289 Strip[24961:207] nib loader, don't let us down...
Program received signal: “EXC_BAD_ACCESS”.
Data Formatters temporarily unavailable, will re-try after a 'continue'. (Not safe to call dlopen at this time.)
(gdb) bt
#0 0x028cd41f in attachMethodLists ()
#1 0x028cdf77 in realizeClass ()
#2 0x028cedad in _class_getNonMetaClass ()
#3 0x028c8eb0 in _class_initialize ()
#4 0x028ce1f6 in prepareForMethodLookup ()
#5 0x028c76c9 in lookUpMethod ()
#6 0x028c7836 in _class_lookupMethodAndLoadCache ()
#7 0x028d5ad3 in objc_msgSend ()
#8 0x00007b81 in -[EntryViewController controllerForFieldType:] (self=0x38cfaf30, _cmd=0x190c8f, type=0x3cacbfe0) at /Users/wgray/Documents/Sources/iPhone/strip-iphone/Classes/EntryViewController.m:482
...snip...
#22 0x00001de4 in main (argc=1, argv=0xbfffefec) at /Users/wgray/Documents/Sources/iPhone/strip-iphone/main.m:14
(gdb)
更新三:情节变厚了。根据@ohorob 在评论中的建议,我添加了环境参数 OBJC_PRINT_INITIALIZE_METHODS=YES 并发现应用程序中的每个类初始化看起来都不错,除了这里有问题的类。每个在控制台输出中看起来都像这样:
objc[26750]: INITIALIZE: calling +[UIPinchGestureRecognizer initialize]
objc[26750]: INITIALIZE: finished +[UIPinchGestureRecognizer initialize]
objc[26750]: INITIALIZE: UIPinchGestureRecognizer is fully +initialized
当我运行应用程序并选择导致爆炸的表行时,我们只看到崩溃前的 nslog 控制台输出,以及崩溃本身。我想这意味着我们可以排除不正确的初始化,但我在运行时方面的专家还不够。
对 master 分支和这个 dev 分支之间的代码差异进行了彻底的审计,并没有发现任何迹象表明我已经踩到了一个指针,但我一直认为这是最有可能的想法。