我的应用程序在模拟器上运行良好,但是当我在设备上测试应用程序时,我最终得到一个随机的 EXC_BAD_ACCESS 并且应用程序崩溃。
经过几天的测试,我想我找到了导致此错误的代码。在某些时候,我需要向控制器的主视图添加一些子视图,然后用户与应用程序交互,这些子视图从他们的超级视图中删除,并添加新的子视图。如果我从不删除子视图,应用程序不会崩溃,但如果我删除它们,应用程序最终会收到 EXC_BAD_ACCESS 并崩溃。
似乎删除的子视图在它们已经完全发布或类似的东西时会获得发布消息……这是我使用 ARC 的第一个应用程序,所以我可能遗漏了一些东西……
这是涉及的代码:
#define kWordXXX 101
#define kWordYYY 102
...
// This is called after the user interaction, it removes the
// old subviews (if they exist) and add new ones
- (void)updateWords
{
[self removeWords];
if (self.game.move.wordXXX) {
WordView *wordXXX = [self wordViewForTypeXXX];
wordXXX.tag = kWordXXX;
// self.wordsView is the view where the subviews are added
[self.wordsView addSubview:wordXXX];
}
if (self.game.move.wordYYY) {
WordView *wordYYY = [self wordViewForTypeYYY];
wordYYY.tag = kWordYYY;
[self.wordsView addSubview:wordYYY];
}
}
// Remove the old words if they exist
- (void)removeWords
{
WordView *wordXXX = (WordView *)[self.wordsView viewWithTag:kWordXXX];
WordView *wordYYY = (WordView *)[self.wordsView viewWithTag:kWordYYY];
if (wordXXX) {
[wordXXX removeFromSuperview];
}
if (wordYYY) {
[wordYYY removeFromSuperview];
}
}
这是子视图的创建方式。我对这段代码并不特别自豪,它需要重构,但我需要了解为什么之前不起作用:
- (WordView *)wordViewWithFrame:(CGRect)frame andType:(WordType)type
{
WordView *wordView = nil;
if (type == SystemWord) {
frame.origin.y += 15;
wordView = [[SystemWordView alloc] initWithFrame:frame];
} else if (type == StartWord) {
wordView = [[StartWordView alloc] initWithFrame:frame];
} else if (type == UserWord) {
wordView = [[UserWordView alloc] initWithFrame:frame];
} else {
wordView = [[RivalWordView alloc] initWithFrame:frame];
}
return wordView;
}
- (WordView *)wordViewForTypeXXX
{
WordType type = self.game.move.wordType;
WordView *wordView = nil;
CGRect wordViewFrame = CGRectMake(0,
0,
self.scoreView.frame.size.width,
35);
wordView = [self wordViewWithFrame:wordViewFrame andType:type];
wordView.word = self.game.move.word;
return wordView;
}
- (WordView *)wordViewForTypeYYY
{
WordType type = self.game.move.wordType;
CGFloat y = self.game.move.word ? 35 : 0;
WordView *wordView = nil;
CGRect wordViewFrame = CGRectMake(0,
y,
self.scoreView.frame.size.width,
35);
wordView = [self wordViewWithFrame:wordViewFrame andType:type];
wordView.word = self.game.move.word;
if (self.game.move.word && [wordView isKindOfClass:[PlayerWordView class]]) {
((PlayerWordView *)wordView).points = [NSNumber numberWithInteger:self.game.move.points];
}
return wordView;
}
这工作了一段时间,然后崩溃。我的意思是,视图被删除并添加了几次,看起来一切正常,但过了一段时间,应用程序获得了 EXC_BAD_ACCESS。
任何帮助将不胜感激!
PS:对不起我的英语
编辑:我不能在设备上使用 Zombies,也看不到堆栈跟踪。
如果我在获得 EXC_BAD_ACCESS 后在 lldb 上键入“bt”,这就是我得到的结果:
* thread #1: tid = 0x2503, 0x3bb735b0 libobjc.A.dylib`objc_msgSend + 16, stop reason = EXC_BAD_ACCESS (code=1, address=0x11d52465)
frame #0: 0x3bb735b0 libobjc.A.dylib`objc_msgSend + 16
frame #1: 0x3473f6fe Foundation`probeGC + 62
frame #2: 0x34745706 Foundation`-[NSConcreteMapTable removeObjectForKey:] + 34
frame #3: 0x360b3d5c UIKit`-[_UIImageViewPretiledImageWrapper dealloc] + 80
frame #4: 0x3bb75488 libobjc.A.dylib`(anonymous namespace)::AutoreleasePoolPage::pop(void*) + 168
frame #5: 0x33e16440 CoreFoundation`_CFAutoreleasePoolPop + 16
frame #6: 0x347ea184 Foundation`__NSThreadPerformPerform + 604
frame #7: 0x33ea8682 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 14
frame #8: 0x33ea7ee8 CoreFoundation`__CFRunLoopDoSources0 + 212
frame #9: 0x33ea6cb6 CoreFoundation`__CFRunLoopRun + 646
frame #10: 0x33e19ebc CoreFoundation`CFRunLoopRunSpecific + 356
frame #11: 0x33e19d48 CoreFoundation`CFRunLoopRunInMode + 104
frame #12: 0x379dd2ea GraphicsServices`GSEventRunModal + 74
frame #13: 0x35d2f300 UIKit`UIApplicationMain + 1120
frame #14: 0x0005bd40 Dr. Cuaicap`main(argc=1, argv=0x2fda8d10) + 116 at main.m:16
frame #15: 0x3bfafb20 libdyld.dylib`start + 4