web-dev-qa-db-ja.com

iOS SDKでUIScrollView EXC_BAD_ACCESSがクラッシュする

ユーザーがコンテンツを作成すると表示および非表示になるビューがいくつかあるiPhone SDKアプリケーションがあります。しばらくデバイスでアプリケーションを使用した後、次のクラッシュが発生します。

Program received signal:  “EXC_BAD_ACCESS”.
(gdb) backtrace
#0  0x33369ebc in objc_msgSend ()
#1  0x320e5248 in -[UIScrollView(UIScrollViewInternal) _scrollViewAnimationEnded] ()
#2  0x338b4a14 in -[NSObject performSelector:withObject:] ()
#3  0x320e5098 in -[UIAnimator stopAnimation:] ()
#4  0x320e4b7c in -[UIAnimator(Static) _advance:] ()
#5  0x320e4a34 in LCDHeartbeatCallback ()
#6  0x34350e60 in HeartbeatVBLCallback ()
#7  0x332e91c0 in IOMobileFramebufferNotifyFunc ()
#8  0x316532f8 in ?? ()
#9  0x33866b50 in __CFMachPortPerform ()
#10 0x338ae52a in CFRunLoopRunSpecific ()
#11 0x338adc1e in CFRunLoopRunInMode ()
#12 0x3434e1c8 in GSEventRunModal ()
#13 0x32002c30 in -[UIApplication _run] ()
#14 0x32001230 in UIApplicationMain ()
#15 0x00002ff8 in main (argc=1, argv=0x2ffff550) at /Developer/svn/MyCompany/iPhone/MyApplication/Other Sources/main.m:14

トレースからわかるように、私のコードで言及されているのはmainの呼び出しだけです。

XcodeからBuild and Analyzeを実行し、ターミナルからプロジェクトでclangアナライザーを実行するように設定しましたが、どちらもコードの問題を検出できません。 iOS SDKの最新リリースバージョンを使用しています(まだ4.1をダウンロードしていませんが、使用しているのは4.1より前のリリースのものです)。

また、シミュレーターを使用してInstrumentsでアプリケーションを実行しましたが、アプリにメモリリークはありません。

NSZombieEnabled変数を使用して何かが見つかるかどうかを確認しようとしていますが、問題は、アプリケーションがクラッシュする前にアプリケーションを30〜40分ほど使用する必要があることであり、NSZombieEnabledは、問題を見つけるのに役立ちません。

私が見たクラッシュは、モーダルビューが親ビューコントローラーのデリゲートを呼び出すときに発生したようです。親ビューコントローラーは、モーダルビューコントローラーを閉じる前に、いくつかの処理を行います。クラッシュにはアニメーション表示とスクロール表示への参照がいくつかありますが、それらに問題を引き起こすために何ができるのかわかりません。誰かが探すべきことについて何か提案がありますか?

編集:NSZombieEnabledフラグをアプリケーションに入れました。デバイスでは、コンソールに次のメッセージが表示されます。

2010-09-11 17:10:33.970 MyApplication[9321:207] *** 
-[MyViewController respondsToSelector:]: message 
sent to deallocated instance 0x7489480

私の知る限りでは、アプリケーションで使用されるデリゲートをすべてのクラスのdeallocsでnilに設定しているので、次にどこを見ればいいのか悩んでいます。

malloc_history pid addressコマンドでこれを実行しましたが、プロセスが見つからなかったため、9321、9321:207、および207を試しました。また、MallocStackLogging変数を使用しようとすると、プログラムはデバイス上で実行すると、malloc:コンソールでスタックログディレクトリメッセージを作成できず、プログラムがクラッシュします。

ああ、ところで、デバイスで動作していないように見えるので、インストゥルメントでゾンビチェックを使用できません。また、シミュレータで同じクラッシュが発生することはありません。

36
BP.

スタックフレーム#1のUIScrollViewは、おそらくデリゲートにアニメーションの終了を通知する必要がありますが、デリゲートはその時点で消えています。 NSZombieEnabledを設定すると、おそらくこれを確認できます。

デリゲートは保持されないため、これはCocoaおよびCocoa Touchの一般的なエラーです。コード内でUIScrollViewまたはUITableViewのデリゲートを探し、その時間より前にリリースされる可能性があるものを見つけてください。

42
Nikolai Ruhe

私はこの問題に自分で取り組みました。

私は問題を抱えていました:

  • ScrollviewデリゲートがUIViewControllerに接続されました
  • スクロールビューがアニメーションを開始しました
  • デリゲートが消え、deallocが呼び出されました。

問題は、スクロールビューデリゲートメッセージが新しく割り当てを解除されたオブジェクトで発生し、クラッシュログが無意味なオブジェクト参照を指しているため、少し混乱していたことです。

修正は、ビューコントローラーのdeallocメソッドの最初の行として、scrollviewデリゲートをnilに設定することでした。

これが誰かを助けることを願っています!

61
Derek Stutsman

完全を期すために、同じスタックトレース(iOS 6)を追加しますが、同じ問題が発生する可能性がありますが、実装が少し異なり、問題を再現するための正確な手順が異なります。

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x71f05631
Crashed Thread:  0

Thread 0 name:  Dispatch queue: com.Apple.main-thread
Thread 0 Crashed:
0   libobjc.A.dylib                 0x3919b5d0 objc_msgSend + 1
1   UIKit                           0x33421830 -[UIScrollView(UIScrollViewInternal) _delegateScrollViewAnimationEnded] + 48
2   UIKit                           0x334217ba -[UIScrollView(UIScrollViewInternal) _scrollViewAnimationEnded:finished:] + 130
3   UIKit                           0x334216a4 -[UIAnimator stopAnimation:] + 460

これはiOS 6で発生しており、UIScrollViewDelegateメソッドを実装したときに発生し始めました。

" -(void)scrollViewDidEndDecelerating:(UITableView *)tableView" 
and made a call to:
"[tableView scrollToRowAtIndexPath: indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];".  

アニメーションが開始し、「戻る」ボタンを押したときに問題が発生し、アニメーションが完了する前にビューコントローラーがポップオフしました。

再生するときは、アニメーションが始まってから完了する前に、必ず「戻る」ボタンを押してください。何度か試してみました。プログラムでビューコントローラーをポップオフして問題を再現しようとしましたが、再現できませんでした。 「戻る」ボタンを使わなければなりませんでした。私は単にdeallocで[myTableView release]を呼び出していました。解決策は、これらのプロパティの両方をnilに設定するためにここで説明したとおりです。

self.myTableView.delegate = nil;
self.myTableView = nil;
16
Chip Bancroft

最初は、デリゲートweak/assignタイプである必要があります。しかし、この場合のイベントには、スクロールアニメーションによって引き起こされる非常に一般的な微妙な障害があります。 ScrollViewsにアニメーションコンテンツオフセットの変更を使用する場合は、そのdelegatenildeallocメソッドに設定する必要があります。

そうでなければ、次のようになります

[YourViewController respondsToSelector:]: message sent to deallocated instance

非常に一般的な例:

1. _tableView is ivar of YourViewController
2. _tableView.delegate = self;
3. - (void)scrollViewDidScroll:(UIScrollView *)scrollView is implemented at YourViewController
4. at some point you call [_tableView scrollToRowAtIndexPath:indexPath 
   atScrollPosition:UITableViewScrollPositionBottom animated:YES];
   or [_tableView setContentOffset:CGPoint animated:YES]
   and try to close YourViewController

_tableViewはCoreAnimationによって保持されますが、YourViewControllerは割り当て解除されます!

7
malex

私の推測では、scrollviewのデリゲートは割り当て解除されたオブジェクトに設定されています。 deallocメソッドで、子オブジェクトのすべてのデリゲートをnilに設定してみてください。

3
rpetrich

これは、更新コントローラーをサブビューとしてテーブルビューに挿入した場合に発生する可能性があります(私のヒントですが、それを行うことはありません)...

2
Peter Lapisu

上記のすべては私の問題を解決しなかったので、もう一度コードを掘り下げました。キーボードとICollectionViewアニメーション(そう、チャットです)を実行して現在のコントローラーを閉じると、クラッシュが発生することを認識しました。

アニメーション完了ブロックでスクロールを作成しようとすると、アプリケーションがクラッシュします:)

切るだけですべてうまくいきます!

幸せなコーディングとデバッグ:)

2
Anton Gaenko

存在しないindexPathを指定してscrollToRowAtIndexPathを呼び出すと、このような動作が見られます

0
trickster77777