1

iOSアプリのクラッシュの問題をデバッグするのに時間がかかっています。でUIViewController定義する場所があります。また、その性質のもの(ビューが回転されている)などのメッセージを送信できるように、のコピーを保持しています。これに加えて、には、親への関連付けを含む独自のデリゲートメンバーがあります(assignを使用し、親への参照を保持しません)。(これはAppleドキュメントの1つで使用されているパターンです-2つのオブジェクト間に循環参照があるため、これは私の問題の一部ではないかと思います)UIViewloadViewUIViewUIView

オブジェクトの階層ビューは次のとおりです。

UIViewController + UIView +NSNotificationCenter UIKeyboardDidShow

この問題は、NSNotificationforUIKeyboardDidShowが発生し、親デリゲートメソッドが呼び出されたときに発生します。代理人が設定されたことを知っています。しかし、どういうわけか、どこかで代理人が解放されています。また、は一度だけ_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

それが問題でした。これ以上のクラッシュはありません。したがって、オブザーバーを絶対に必要な場合にのみ登録し、不要な場合は登録を解除するようにしてください。

4

1 に答える 1

1

オブジェクトの割り当てが解除されたタイミングを確認するには、NSLogをそのdeallocルーチンに配置します。また、アドレスストップをに配置するdeallocと、コールスタックを表示してrelease、オブジェクトを解放するために誰が実行しているかを確認できます。

オブジェクトが実際には思ったよりも早く割り当て解除されているのではないかと思いますが、タイマーイベント中にストレージがリサイクルされ、エラーが検出されます。

于 2012-05-17T01:46:07.550 に答える