私のアプリはシミュレーターで完全に動作していますが、デバイスでアプリをテストすると、最終的にランダムな 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: 私の英語でごめんなさい
編集:デバイスでゾンビを使用できず、スタックトレースが表示されません。
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