My app is working perfectly on the simulator but when I test the app on the device I eventually get a random EXC_BAD_ACCESS and the app crashes.
After a few days of testing I think I have found the code that is causing this error. At some point I need to add some subviews to a controller's main view, then the user interacts with the app and those subviews are removed from their superview and new subviews are added. If I don't ever remove the subviews the app does not crash but if I remove them, the app eventually gets an EXC_BAD_ACCESS and crashes.
It seems like the subviews removed get a release msg when they already are completely released or something like that... This the first app where I'm using ARC so I'm probably missing something...
Here's the code involved:
#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];
}
}
Here is how the subviews are created. I'm not particularly proud of this code and it needs refactoring but I need to understand why is not working before:
- (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;
}
This is working for a while and then crashes. I mean, the views are removed and added a few times and it seems like everything is OK but after a while the app gets the EXC_BAD_ACCESS.
Any help will be eternally appreciated!
PS: Sorry for my English
EDIT: I can't use Zombies on the device and I can't see the stacktrace.
This is what I get if I type "bt" on the lldb after I get the EXC_BAD_ACCESS:
* 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