40

UIViewControllerサブクラス内に次のメソッドがあるとします。

- (void)makeAsyncNetworkCall
{
    [self.networkService performAsyncNetworkCallWithCompletion:^{
        dispatch_async(dispatch_get_main_queue(), ^{
                [self.activityIndicatorView stopAnimating];
            }
        });
    }];
}

selfブロック内への参照により、UIViewControllerインスタンスがブロックによって保持されることはわかっています。performAsyncNetworkCallWithCompletionのプロパティ (または ivar) にブロックを保存しない限り、NetworkService保持サイクルがないと考えるのは正しいですか?

performAsyncNetworkCallWithCompletion上記の構造により、システムによって以前にリリースされたとしても、終了するまで UIViewController が保持されることになります。しかし、 ( iOS 6 が aのバッキングメモリを管理する方法が変更されUIViewController 後) システムが my の割り当てを解除する可能性は高いでしょうか (または可能でしょうか? )。UIViewControllerCALayer

「weakSelf/strongSelf ダンス」をしなければならない理由があるとすれば、次のようになります。

- (void)makeAsyncNetworkCall
{
    __weak typeof(self) weakSelf = self;
    [self.networkService performAsyncNetworkCallWithCompletion:^{
        typeof(weakSelf) strongSelf = weakSelf;
        if (!strongSelf) {
            return;
        }
        dispatch_async(dispatch_get_main_queue(), ^{
                [strongSelf.activityIndicatorView stopAnimating];
            }
        });
    }];
}

しかし、これは無意識に醜いので、必要がない場合は避けたいと思います。

4

4 に答える 4

8

問題は、networkService がブロックへの強い参照を保持している可能性があることだと思います。また、View Controller は networkService への強い参照を持つ場合があります。したがって、VC->NetworkService->block->VCの可能なサイクルが存在する可能性があります。ただし、この場合、ブロックは実行後に解放されると想定するのが通常安全です。この場合、サイクルは壊れています。したがって、この場合は必要ありません。

ブロックが解放されていない場合に必要です。たとえば、ネットワーク呼び出しの後に 1 回実行されるブロックの代わりに、コールバックとして使用されるブロックがあるとします。つまり、networkService オブジェクトはブロックへの強力な参照を維持し、それをすべてのコールバックに使用します。この場合、ブロックは VC への強い参照を持ち、これにより強いサイクルが作成されるため、弱い参照が優先されます。

于 2014-01-14T13:32:11.310 に答える
3

いいえ、self.networkService がブロック プロパティとして使用しない場合は問題ありません。

于 2014-01-14T13:07:56.487 に答える
1

ここでの答えはそれほど単純ではありません。@Robの回答に同意しますが、追加の説明が必要です:

  1. __weakUIViewControllerリリース時に自己をゼロにするため、安全な方法と見なされます。つまり、スタックからポップされたように、呼び出し元のオブジェクトが既にリリースされ、ブロックによって参照されているときにコールバックが発生しても例外はありません。あらゆる種類の操作をキャンセルする可能性を追加することは、彼女の単なる衛生問題であり、おそらくリソースの問題でもあります. たとえば、単に cancel もできます。キャンセルできるNSURLConnectionのはそれだけNSOperationではありません。ブロックにコールバックするメソッドで非同期に実行されているものは何でもキャンセルできます。

  2. self がブロックによって保持される場合、呼び出し元オブジェクトのようなUIViewControllerものが解放されUINavigationController、ブロックがまだそれを保持してコールバックする場合、ストーリーは少し複雑になる可能性があります。この場合、コールバック ブロックが実行され、その結果によって一部のデータが変更されると想定されます。それは望ましい振る舞いかもしれませんが、ほとんどの場合そうではありません。したがって、この場合、操作のキャンセルがより重要になる可能性があり、関連付けられたオブジェクトまたはシングルトンとしてUINavigationControllerDelegate存在する可変コレクションから非同期タスクをキャンセルすることにより、メソッドで非常に賢明になります。UINavigationController

もちろん、セーブベットは最初のオプションを使用しますが、呼び出し元オブジェクトを閉じた後に非同期操作を続行したくない場合に限ります。

于 2014-07-11T11:46:57.020 に答える