0

Matt GallowayによるEffective Objective-Cの本から入手したコードスニペットを研究しています。スニペットは次のとおりです(少し変更しました)。

- (void)downloadData {
    NSURL *url = // alloc-init
    NetworkFetcher *networkFetcher =
        [[NetworkFetcher alloc] initWithURL:url];
    [networkFetcher startWithCompletionHandler:^(NSData *data){
        NSLog(@"Request URL %@ finished", networkFetcher.url);
        _fetchedData = data;
    }];
    // ARC will put a release call for the networkFetcher here
}

著者が述べたように、このようなパターンはさまざまなネットワーク ライブラリで使用され、保持サイクルがあります。オブジェクト グラフの観点から考えると、networkFetcherインスタンスはcompletionHandlerプロパティ ( copyied ) を介してブロックを保持するのに対し、ブロックはnetworkFetcherで使用するため を保持するため、保持サイクルは私にとって非常に明白ですNSLog

ここで、ブロックを解除するには、データのダウンロードが完了したときにNetworkFetcher完了ハンドラーを設定する必要があります。nil

// in NetworkFetcher.m class
- (void)requestCompleted {

    if(self.completionHandler) {
        // invoke the block
        self.completionHandler();
    }

    self.completionHandler = nil;
}

Ok。このようにして、保持サイクルはもうありません。ブロックは、実行されると、 への参照を解放し、networkFetcherはブロックへの参照をnetworkFetcher作成nilします。

さて、私の質問はスニペットの実行フローに関するものです。次の一連の動作は正しいですか?

  1. networkFetcher完了ハンドラを実行します
  2. ブロックが実行されます
  3. ブロックはへの参照を解放しますnetworkFetcher
  4. networkFetcherブロックへの参照を解放する

私の疑問は、アクション 3) と 4) に依存しています。3) が 4) の前に実行された場合、誰も参照を持っていないnetworkFetcherため、いつでも解放できます (ARC は の最後に解放呼び出しを配置し​​ますdownloadData)。私は間違っていますか、それとも何か不足していますか?

質問が明確であることを願っています。

4

2 に答える 2

3
// in NetworkFetcher.m class
- (void)requestCompleted {

    if(self.completionHandler) {
        // invoke the block
        self.completionHandler();
    }

    self.completionHandler = nil;
}

ブロックはnil に設定される前に実行されます。このメソッドでは、ブロックの実行は同期的です。実行が完了するまで何も起こりません。ブロックの存在は、内部のコードが非同期で実行されることを意味しないことに注意してください。

ブロックはネットワーク フェッチャー インスタンスのプロパティとしてまだ存在するため、ブロックは実行後にその参照を解放しません。少し変わっていれば、もう一度実行できます。

ブロックは、割り当てが解除されたときにキャプチャしたオブジェクトのみを解放します。これは、ブロックが実行された後で、completionHandler プロパティが nil に設定されたときに発生します。

于 2014-04-19T16:03:30.217 に答える