iOSアプリのクラッシュの問題をデバッグするのに時間がかかっています。でUIViewController
定義する場所があります。また、その性質のもの(ビューが回転されている)などのメッセージを送信できるように、のコピーを保持しています。これに加えて、には、親への関連付けを含む独自のデリゲートメンバーがあります(assignを使用し、親への参照を保持しません)。(これはAppleドキュメントの1つで使用されているパターンです-2つのオブジェクト間に循環参照があるため、これは私の問題の一部ではないかと思います)UIView
loadView
UIView
UIView
オブジェクトの階層ビューは次のとおりです。
UIViewController
+ UIView
+NSNotificationCenter UIKeyboardDidShow
この問題は、NSNotification
forUIKeyboardDidShow
が発生し、親デリゲートメソッドが呼び出されたときに発生します。代理人が設定されたことを知っています。しかし、どういうわけか、どこかで代理人が解放されています。また、は一度だけ_bufferViewDelegate
設定されます。最後に、これは毎回発生するわけではありません。それはめったに起こりません。
スタックトレースは次のとおりです。
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x00000000, 0x00000000
Crashed Thread: 0
Last Exception Backtrace:
0 CoreFoundation 0x325f288f __exceptionPreprocess + 163
1 libobjc.A.dylib 0x34648259 objc_exception_throw + 33
2 CoreFoundation 0x325f5a9b -[NSObject doesNotRecognizeSelector:] + 175
3 CoreFoundation 0x325f4915 ___forwarding___ + 301
4 CoreFoundation 0x3254f650 _CF_forwarding_prep_0 + 48
5 Buffer 0x0008716d -[BufferView scrollToCursor] (BufferView.m:4348)
6 Buffer 0x00080407 -[BufferView keyboardDidShow:] (BufferView.m:1379)
7 Foundation 0x37f3d4ff __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_0 + 19
8 CoreFoundation 0x325be547 ___CFXNotificationPost_block_invoke_0 + 71
9 CoreFoundation 0x3254a097 _CFXNotificationPost + 1407
10 Foundation 0x37eb13eb -[NSNotificationCenter postNotificationName:object:userInfo:] + 67
11 UIKit 0x3209f029 -[UIInputViewTransition postNotificationsForTransitionEnd] + 789
12 UIKit 0x3233a51f __53-[UIPeripheralHost(UIKitInternal) executeTransition:]_block_invoke_01008 + 159
13 UIKit 0x320344db -[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] + 215
14 UIKit 0x3202eaab -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 471
15 UIKit 0x320343d5 -[UIViewAnimationState animationDidStop:finished:] + 53
16 QuartzCore 0x342dbc2f CA::Layer::run_animation_callbacks(void*) + 203
17 libdispatch.dylib 0x35c4ae91 _dispatch_main_queue_callback_4CF$VARIANT$up + 197
18 CoreFoundation 0x325c52ad __CFRunLoopRun + 1269
19 CoreFoundation 0x325484a5 CFRunLoopRunSpecific + 301
20 CoreFoundation 0x3254836d CFRunLoopRunInMode + 105
21 GraphicsServices 0x3169f439 GSEventRunModal + 137
22 UIKit 0x32047cd5 UIApplicationMain + 1081
23 Buffer 0x0005c20b main (main.m:20)
24 Buffer 0x0005bcac start + 40
更新2:
問題を解決しました。私がしたことは、コントローラーとすべてのサブビューの両方にNSLogステートメントを入れて、すべてが期待どおりにリリースされているかどうかを判断することでした。そうではありませんでした。私が期待し、ほとんどの場合に発生したのは、これでした。
UIViewController loadView <-- Open the view, init the BufferView
UIViewController dealloc
BufferView dealloc
何が起こっていたのかというと、BufferViewのdeallocメソッドが呼び出されないことがありました。
UIViewControllerのコードは次のようになりました。
- (void)loadView
{
...
// bufferView is a member var of this particular UIViewController
bufferView = [[BufferView alloc] init];
[self addSubview:view];
...
}
UIViewControllerのdeallocメソッドが呼び出されたときに、bufferViewを解放しました。
- (void)dealloc
{
...
[bufferView release];
bufferView = nil;
...
[super dealloc];
}
loadViewでコードをこれに変更したとき:
- (void)loadView
{
...
// bufferView is a member var of this particular UIViewController
bufferView = [[BufferView alloc] init];
[self addSubview:view];
[bufferView release];
...
}
そしてdeallocのreleaseコマンドを削除すると、すべてが期待どおりに機能し始めました。サブビューに追加した後にビューを解放するのがベストプラクティスのようです。私は他のアプリケーションでこのパターンを見たことがありますが、なぜこのようにする必要があるのか理解できませんでした。これが他の誰かを助けることを願っています。
私は1日以上クラッシュを経験していないことに注意してください。これは以前よりもずっと良くなっています。これが間違った解決策であることが判明した場合は、チケットを更新します。
更新3
上記は機能しませんでした。UIViewController viewWillAppear、viewDidDisappearメソッドで通知を登録/登録解除しています。問題が解決しました。私が知る限り、皆さんの提案は[[NSNotification defaultCenter] removeObserver:self]呼び出しをdeallocに入れることです。これはまったく良い考えではありません。発生が予想される時間枠内にオブジェクトの割り当てを解除するためにシステムに依存することはできません。場合によっては問題なく動作することもありますが、すべてではありません。必要な場合にのみ、通話の登録/登録解除を試みることをお勧めします。私の場合、ビューが表示されているときにのみ必要であり、ビューが表示されていないときに登録を解除します。1日はクラッシュしません(それがどのくらい続くかを確認します)。数日以内に更新して成功します。
更新4
それが問題でした。これ以上のクラッシュはありません。したがって、オブザーバーを絶対に必要な場合にのみ登録し、不要な場合は登録を解除するようにしてください。