5

アプリでネットワークを必要とするオブジェクトの「インターネット対応」基本クラスがあります。インターネット対応である必要があるすべてのオブジェクトは、それを継承します。ご想像のとおり、私はこれらのオブジェクトの多くを割り当ておよび割り当て解除します。

インターネット対応の基本クラスには、インターネットステータスのチェックに使用される到達可能性クラスと対話するための次のコードがあります。

#import "Reachability.h"

- (id) init {
    ...
    self.internetReachable = [Reachability reachabilityForInternetConnection];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(checkNetworkStatus) name:kReachabilityChangedNotification object:nil];
    [self.internetReachable startNotifier];
    ...
  }
- (void)  dealloc
 {
    [self.internetReachable stopNotifier];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
 }

アプリのインターネットステータスが変更されるとすぐに、アプリは次のエラーでクラッシュします。

***-[Reachability isKindOfClass:]:割り当て解除されたインスタンス0x1e249a30に送信されたメッセージ

ゾンビをオンにして、Reachability.m内の次のコード行まで問題を追跡しました

NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");

残念ながら、NSNotifcationsのリッスンを停止して通知機能を停止する以外に、このエラーを回避するためにオブジェクトが他に何ができるかわかりません。

どんな助けや提案も素晴らしいでしょう。

ありがとう

Vb

編集:

さて、以下の回答のアドバイスに従って、割り当てのある機器で実行しました。これが保持カウントの履歴でした。

ここに画像の説明を入力してください

私が疑ったように、私が割り当てを解除したオブジェクトは、私自身ではなく、Foundation(つまり、NSNotifcationCenter)によって呼び出されています。

私のインターネットオブジェクトには、Reachabilityオブジェクトへの強力なポインタがあります。それらの割り当てが解除されると、Reachabilityオブジェクトも割り当て解除されます。ゾンビは到達可能性オブジェクトです。インターネットオブジェクトのdeallocでremoveObserverを呼び出しましたが、Foundationはまだ割り当て解除されたオブジェクトを呼び出しています。理由がわからない...

4

3 に答える 3

7

Foundationが割り当て解除されたReachabilityにNSNotifcationsを送信している理由は、Reachabilityオブジェクトが、作成されていたスレッドとは異なるスレッドで割り当て解除されていたためです。到達可能性はスレッドセーフではありません。Reachabilityオブジェクトが作成されていたのと同じキューにdispatch_asyncを使用して戻すと、問題が解決しました。

于 2013-03-21T18:59:36.807 に答える
4

これは、Reachabilityをインスタンス化するために作成したオブジェクト、つまりReachabilityインスタンスへの参照を保持しているオブジェクトが、stopNotifierを呼び出さずに(または呼び出す前に)割り当て解除された場合に発生します。

これを解決するのはとても簡単です。オブジェクトがスタックから削除されて到達可能性インスタンスが破棄される前に、stopNotifierを呼び出す必要があります。これはdeallocメソッドで実行できます。または、viewControllerの場合は、viewDidDisappearなどのライフサイクルメソッドの1つで呼び出すことができます。

ここでスレッドをいじる必要はありません。ReachabilityでstartNotifierを呼び出す場合、これはReachabilityの設計によりバックグラウンドスレッドで開始されることを考慮してください。したがって、stopNotifierを呼び出すと、スレッド化が自動的に処理されます。

スレッドをいじる必要がある理由は、Reachabilityへの参照を保持しているオブジェクトの割り当てが解除されたが、startNotifierで発生したネットワーク変更の登録済みリスナーであったという事実と関係があります。ネットワークが変更された場合、通知を受信するように登録されていても、オブジェクトがどこにも見つからないことを推測してください。クラッシュクラッシュ。stopNotifierは、停止する前に登録を解除し、すべてが正常に機能します。

- (void)dealloc
{ // self.hostReachability is my property holding my Reachability instance
    if (self.hostReachability) {
        [self.hostReachability stopNotifier];
    }
}
于 2014-10-21T16:45:38.660 に答える
1

NSCAssert行は、割り当て解除されたオブジェクトに最初にアクセスする場所ですが、オブジェクトのライフサイクルについて詳しく知りたい場合は、Instrumentsを使用する必要があります。Xcodeのプロファイルツールを使用して、割り当て(リークではありません!)ツールを使用してシミュレータでプログラムを実行します。割り当てツールの起動構成で、[NSZombie検出レコード参照カウントを有効にする]をオンにします。NSCAssert行に到達すると、Instrumentsはゾンビ情報オブジェクトにメッセージを送信する試みを検出し、それをメモする必要があります。ゾンビ情報オブジェクトの詳細情報を見ると、Instrumentsは参照カウントの履歴を表示し、割り当てが解除された時期を確認できるはずです。

于 2013-03-21T18:13:59.567 に答える