2012-01-07 11 views
17

このクラッシュは、iPadとiPad 2の両方でiOS 5を実行しているCrashlyticsでかなり頻繁に見られています。メモリ警告が原因であるようですが、私のアプリケーションコードを参照してください、ちょうどiOSフレームワーク:UIViewController purgeMemoryForReason:iOS 5でクラッシュする

0 libobjc.A.dylib objc_msgSend + 15 
1 UIKit   -[UIViewController purgeMemoryForReason:] + 64 
2 Foundation  __57-[NSNotificationCenter addObserver: selector: name: object:]_block_invoke_0 + 18 
3 CoreFoundation  ___CFXNotificationPost_block_invoke_0 + 70 
4 CoreFoundation  _CFXNotificationPost + 1406 
5 Foundation  -[NSNotificationCenter postNotificationName: object: userInfo:] + 66 
6 Foundation  -[NSNotificationCenter postNotificationName: object:] + 30 
7 UIKit   -[UIApplication _performMemoryWarning] + 80 
8 UIKit   -[UIApplication _receivedMemoryNotification] + 174 
9 libdispatch.dylib _dispatch_source_invoke + 516 
10 libdispatch.dylib _dispatch_queue_invoke + 50 
11 libdispatch.dylib _dispatch_main_queue_callback_4CF + 156 
12 CoreFoundation  __CFRunLoopRun + 1268 
13 CoreFoundation  CFRunLoopRunSpecific + 300 
14 CoreFoundation  CFRunLoopRunInMode + 104 
15 GraphicsServices GSEventRunModal + 156 
16 UIKit   UIApplicationMain + 1090 
17 500px iOS  main.m line 12 

私は最高と低いがグーグルがこれに対する解決策を見つけることができません。これは、UIViewControllerインスタンスを過剰にリリースしたために発生したようですが、私はARCを使用していますので、どうしてそんなことが起こるのかわかりません。

私はこれに近づく方法を失っています。どのUIViewControllerサブクラスが問題を引き起こしているのかもわかりません。私はシミュレータとデバイス上で問題を再現しようとしましたが、原因を見つけることができません。このようなことを誰かが見たことがありますか、問題の再現にアプローチする方法についての提案がありますか?

+2

興味深い。通常、スタックの次のステップは、そのviewControllerのunloadViewIfReloadable呼び出しです。クラッシュが現れたので、この方法はまだ達成されていないか、すでにそのステップの後ろに乗っていることを意味します。後者については、viewDidUnloadメソッドの実装を確認してください。それが私が検討する次のステップになります。標準的な推奨として、ゾンビを有効にし、シミュレータ上でメモリ警告をトリガします。 – Till

+0

私はそのショットを与え、あなたに戻ってきます。ありがとう! –

答えて

17

私はこの問題を解決したと思います。私はそれについて考えていましたが、問題はUIViewControllerビューのアンロードではなく、実際のメモリ不足通知のポストです。私のコードには、[[NSNotificationCenter defaultCenter] removeObserver:self]といういくつかのインスタンスがあります。これはdeallocメソッドでは問題ありませんが、viewDidUnloadメソッドに2つのインスタンスがありました。

UIViewControllerのいずれかのdidReceiveMemoryのブレークポイントがヒットしなかったとき、これが気付きました。 viewDidUnloadのコードは、他のシステム通知のselfも登録解除しました。詳細はhereです。

クラッシュが新しいアップデートで停止することを確認するまで、私はこれを受け入れられる回答としてマークしません。

更新:問題が修正されたことをCrashlyticsで確認しました。

+2

ええ、通知監視のゴールデンルール:あなたが登録した通知についてのみオブザーバーを削除してください。私はもう少し前にそれについて読んだことがありますが、その結果を決して満たしたことはありません。あなたの問題を修正してうれしいです。 – iHunter

+0

@AshFurrow viewDidUnload _only_上の通知から自分自身を削除します。 – Till

+0

@問題は、UIViewControllerは、私がviewDidUnloadで登録を解除している初期化の通知を登録しているようです。 removeObserver:removeObserver:name:object:を変更しました。これにより、特定の通知のみを登録解除しています。 –

8

私は私の中のdealloc以外[[NSNotificationCenter defaultCenter] removeObserver:self]never calledのiOS 5

上で実行されているデバイスのためにHockeyAppによって報告されたクラッシュの正確な同じスタックトレースに気づいたので、これはクラッシュの原因となることができませんでした。

ここで私はクラッシュを再現できました:MasterViewController私はDetailViewControllerを押してから、戻るボタンをタップしてポップアップします。最後に、メモリ警告が表示され、クラッシュが発生します(iOS 5のみ)。

それはSVPullToRefreshを使用した場合DetailViewControllerインスタンスがあるため保持サイクルのポップされた後に解放されていないことが判明:

@implementation DetailViewController 

- (void) viewDidLoad 
{ 
    [super viewDidLoad]; 

    [self.scrollView addPullToRefreshWithActionHandler:^{ 
     [self refresh]; 
    }]; 
} 

@end 

DetailViewControllerが解除されていないので、それはまだメモリの警告の通知のために登録して、これは何です起こる:

frame #0: 0x0004d61b MyApp`-[DetailViewController dealloc](self=0x089a5150, _cmd=0x024d2738) + 27 at DetailViewController.m:103 
frame #1: 0x0227ae3d libobjc.A.dylib`_objc_rootRelease + 47 
frame #2: 0x0227ae00 libobjc.A.dylib`objc_release + 48 
frame #3: 0x0227c047 libobjc.A.dylib`objc_storeStrong + 39 
frame #4: 0x0004e44c MyApp`__destroy_helper_block_ + 44 at DetailViewController.m:157 
frame #5: 0x029b555d libsystem_sim_blocks.dylib`_Block_release + 166 
frame #6: 0x0227ae00 libobjc.A.dylib`objc_release + 48 
frame #7: 0x0227c047 libobjc.A.dylib`objc_storeStrong + 39 
frame #8: 0x00084c8d MyApp`-[SVPullToRefreshView .cxx_destruct](self=0x08bf3af0, _cmd=0x00000001) + 525 at UIScrollView+SVPullToRefresh.m:121 
frame #9: 0x0226630d libobjc.A.dylib`object_cxxDestructFromClass + 104 
frame #10: 0x02270fde libobjc.A.dylib`objc_destructInstance + 38 
frame #11: 0x02271015 libobjc.A.dylib`object_dispose + 20 
frame #12: 0x0247a9a1 CoreFoundation`-[NSObject dealloc] + 97 
frame #13: 0x00a8cdc7 UIKit`-[UIView dealloc] + 748 
frame #14: 0x0227ae3d libobjc.A.dylib`_objc_rootRelease + 47 
frame #15: 0x00a90b73 UIKit`-[UIView(Hierarchy) removeFromSuperview] + 194 
frame #16: 0x00a8cc10 UIKit`-[UIView dealloc] + 309 
frame #17: 0x00a9d6ff UIKit`-[UIScrollView dealloc] + 405 
frame #18: 0x013ab36c Foundation`NSKVODeallocate + 105 
frame #19: 0x0227ae3d libobjc.A.dylib`_objc_rootRelease + 47 
frame #20: 0x00b21c12 UIKit`-[UIViewController setView:] + 447 
frame #21: 0x00b21885 UIKit`-[UIViewController unloadViewForced:] + 117 
frame #22: 0x00b2180b UIKit`-[UIViewController unloadViewIfReloadable] + 41 
frame #23: 0x00b256ff UIKit`-[UIViewController purgeMemoryForReason:] + 75 
frame #24: 0x00b2563b UIKit`-[UIViewController didReceiveMemoryWarning] + 41 
frame #25: 0x00b2560d UIKit`-[UIViewController _didReceiveMemoryWarning:] + 33 
frame #26: 0x0141ca29 Foundation`__57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_0 + 40 
frame #27: 0x02443855 CoreFoundation`___CFXNotificationPost_block_invoke_0 + 85 
frame #28: 0x02443778 CoreFoundation`_CFXNotificationPost + 1976 
frame #29: 0x0136119a Foundation`-[NSNotificationCenter postNotificationName:object:userInfo:] + 98 
frame #30: 0x0136db03 Foundation`-[NSNotificationCenter postNotificationName:object:] + 55 
frame #31: 0x00a64cf4 UIKit`-[UIApplication _performMemoryWarning] + 91 
frame #32: 0x00a64e00 UIKit`-[UIApplication _receivedMemoryNotification] + 180 
frame #33: 0x00a64f98 UIKit`__block_global_0 + 36 
frame #34: 0x029f1450 libdispatch.dylib`_dispatch_source_invoke + 719 
frame #35: 0x029edcc4 libdispatch.dylib`_dispatch_queue_invoke + 66 
frame #36: 0x029ee4cf libdispatch.dylib`_dispatch_main_queue_callback_4CF + 295 
frame #37: 0x023af803 CoreFoundation`__CFRunLoopRun + 2003 
frame #38: 0x023aed84 CoreFoundation`CFRunLoopRunSpecific + 212 
frame #39: 0x023aec9b CoreFoundation`CFRunLoopRunInMode + 123 
frame #40: 0x038d07d8 GraphicsServices`GSEventRunModal + 190 
frame #41: 0x038d088a GraphicsServices`GSEventRun + 103 
frame #42: 0x00a5a626 UIKit`UIApplicationMain + 1163 
frame #43: 0x00002b82 MyApp`main(argc=1, argv=0xbffff318) + 178 at main.m:15 

または英語で:SVPullToRefreshViewインスタンスがアンロードされるビューの結果として放出されます。 SVPullToRefreshViewインスタンスは、DetailViewControllerへの参照を保持する最後のオブジェクトであるため、解放され、割り当てが解除されます。しかし、purgeMemoryForReason:は依然としてであり、ちょうど割り当て解除されたビューコントローラ(つまり、クラッシュ)で(つまりインスタンス変数にアクセスする)を行っていました。

診断が完了したら、解決策は非常に簡単でした。まず、保持サイクルを避けてください。

@implementation DetailViewController 

- (void) viewDidLoad 
{ 
    [super viewDidLoad]; 

    __typeof__(self) __weak weakSelf = self; 
    [self.scrollView addPullToRefreshWithActionHandler:^{ 
     [weakSelf refresh]; 
    }]; 
} 

@end 
+0

ここでのバグの1つは、purgeMemoryForReasonは自分の仕事をする前に自分自身を保持しておらず、終了後に自分自身を解放するということです。もう1つは、VCがビュー階層との強力な接続を持たず、ビュー階層の解体に成功したと仮定したことです。 –

関連する問題