5

この問題はここここで議論されていますが、デリゲートがあるかどうかに関係なく、これを解決するためのより確実な方法があるのではないかと思います-関数が遅延後に呼び出される場合。プログラムのある時点でボタンを押すと、オブジェクト (CCLayer) が作成されます。そのレイヤーはいくつかのオブジェクトを作成し、そのうちのいくつかはコールバックで作成されます。その作成されたオブジェクト レイヤーには、それを破棄する「戻る」ボタンがあります。オブジェクトが破棄された後にコールバックなどがトリガーされ、もう存在しないオブジェクトにアクセスしようとすると、問題が発生します。「割り当て解除されたインスタンス 0x258ba480 に送信されたメッセージ」がこの良いニュースを提供します。どうすればそれを回避できますか?

1)コールバックを強制終了する方法はありますか(明らかにもう必要ないため)2)コールバック自体でこれらの存在しない可能性のあるオブジェクトの存在をテストする必要があります/テストできますか3)何か他のものはありますか?

(私のコールバックは、Reachability を使用して、この輝かしい Web サイトからコピーしたインターネット接続をチェックするためのコードです。子ビューですが、私はしたくありません。)

- (void)testInternetConnection
{
    internetReachableFoo = [Reachability reachabilityWithHostname:@"www.google.com"];

    // Internet is reachable
    internetReachableFoo.reachableBlock = ^(Reachability*reach)
    {
         // Update the UI on the main thread
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"Yayyy, we have the interwebs!");
            //I do the net stuff here
    });
};

// Internet is not reachable
internetReachableFoo.unreachableBlock = ^(Reachability*reach)
{
    // Update the UI on the main thread
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"Someone broke the internet :(");
        noNetMessageLabel.visible=true; //<-------this goes kaboom
        noNetFlag=true;

    });
};

[internetReachableFoo startNotifier];

}

4

2 に答える 2

5

割り当て解除されたデリゲートにメッセージが送信されないようにするには、基本的に 2 つの方法があります。

  1. 後でメッセージを送信したいオブジェクトを保持します。そうすれば、割り当てが解除されることはありません。これはブロック コールバックの場合です。ブロックが何らかのオブジェクトを参照する場合、そのオブジェクトはブロックが存在しなくなるまで保持されます。ブロックからいくつかのオブジェクトにメッセージを送信し、割り当てが解除されたオブジェクトにヒットした場合、どこかでメモリ管理を台無しにしたに違いありません。

  2. デリゲートを解放する前に、デリゲート リンクをクリアします。nil現在、これは通常、参照されたオブジェクトの割り当てが解除されたときに自動的に設定される弱いゼロ化プロパティを使用して行われます。とても便利。あなたの場合ではありません。

于 2013-10-01T13:41:46.020 に答える
3

いくつかのオプションを検討できます。

まず、オブジェクトにメッセージを渡す前にオブジェクトの存在を確認するだけです:

if (noNetMessageLabel)
  noNetMessageLabel.visible = true;

しかし、個人的にはそれは悪いアーキテクチャだと考えています。

私の観点からすると、より賢明な決定は、インターネット接続に関するアラートを表示するコードをモデルに移動することです。AppDelegate またはモデルで次のようなメソッドを作成します。

- (NSError*)presentConnectivityAlert
{
   if () //any error condition checking appropriate
       [[NSNotificationCenter defaultCenter]
          postNotificationName:@"connectivityAlert"
          object:self
          userInfo:userInfo];
}

また、インターネット チェック コードをモデルに移動することも検討してください。

アプリの ViewControllers で、この通知をリッスンするように実装します。

- (void)viewDidLoad {
    [[NSNotificationCenter defaultCenter] 
      addObserver:self
      selector:@selector(didReceiveRemoteNotification:)                                                  
      name:@"connectivityAlert"
      object:nil];
}

- (void)viewDidUnload {
[[NSNotificationCenter defaultCenter] 
  removeObserver:self
  name:@"connectivityAlert"
  object:nil];
}

-(void)didReceiveRemoteNotification:(NSDictionary *)userInfo {
   if (self.isViewLoaded && self.view.window) {
      //Present the user with alert
   }
}

したがって、すべてのアプリケーション全体で接続の問題を処理するための、より一般的で非常に用途の広いアプローチがあります。

コールバックを強制終了する方法はありますか

ブロックをキャンセルすることはできませんが (あなたの場合)、NSOperationQueue で NSOperation をキャンセルすることは可能です。しかし、それには Reachability の実装を書き直す必要があります。

于 2013-10-01T14:02:28.907 に答える