3

ここに同様の質問がありますが、これは私が望むものを正確に説明していません: Objective C Blocks as Async-callbacks & BAD ACCESS

非同期コールバックでサービスを呼び出すビュー コントローラーがあります。コールバックは、ブロックを使用して実行されます。このブロックは、View Controller の変数を参照して変数を設定します。

次のようになります。

- (void) loadData {
    __block MyViewController *me = self;
    [self.service executeWithCompletion:^(NSArray *result, NSError *error) {
        if (!error) {
            me.data = result;  
        }
    }];
}

ただし、View Controller の割り当てを解除すると、「me」はコールバックによって不正にアクセスされます。

「私」をNULLにする最も簡単な方法は何ですか? iVar として配置すると、循環参照が返されます...と思いますか?

明らかな何かが欠けていると思います....

ありがとう

4

3 に答える 3

5

iOS 5.0 以降 (または Mac OS X 10.7 以降) をターゲットにしていますか? その場合は、ARC と__weak変数 (変数の代わりに__block) を使用できます。参照されたオブジェクトの割り当てが解除されると、これは自動的にゼロになります。あなたのコードは次のようになります

- (void)loadData {
    __weak MyViewController *me = self;
    [self.service executeWithCompletion:^(NSArray *result, NSError *error) {
        if (!error) {
            MyViewController *strongMe = me; // load __weak var into strong
            if (strongMe) {
                strongMe.data = result;
            }
        }
    }];
}

古い OS のサポートが必要な場合は、別のソリューションを見つける必要があります。1 つの解決策は、先に進んでブロックを保持することselfです。サービスが完了ブロックを実行する (そして解放する) ことが保証されている場合、これは完了ブロックが実行されると自動的に中断される一時的なサイクルのみを生成します。または、サービスをキャンセルする何らかの方法がある場合 (キャンセル後にブロックが呼び出されないことを保証する方法で)、 をそのまま__blockにして、 でサービスをキャンセルするようにしてください-dealloc。他の選択肢もありますが、より複雑です。

于 2012-06-05T21:16:54.433 に答える
1

提案から上記のものを組み合わせました。ブロックの消去を含む。ただし、私のオブジェクトはまだすぐに解放されません。つまり、MyViewController の dealloc にブレークポイントを設定します。__block 変数がないと、(おそらく非同期接続が原因で) かなり後の時点で呼び出され、まったく呼び出されないこともあります。

コードはかなり複雑です。そのため、上記のように機能しない原因は他にもあると思います。

私も行ったことは、Mike AshのMAZeroingWeakRefを使用しています。これは、@KevinBallardが提案した__weakを使用するのと同じだと思います。

以下は私がそれを実装した方法であり、動作しているようです。私が望むView Controllerの破棄時にDeallocがすぐに呼び出されます。そして、私はそれをクラッシュさせることができません...そして、私が入れたログコメントで、私が弾丸をかわしていることをすでに見ることができます.

- (void) loadData {
    __block MAZeroingWeakRef *zeroWeakRef = [[MAZeroingWeakRef alloc] initWithTarget:self];
    [zeroWeakRef setCleanupBlock: ^(id target) {
        [zeroWeakRef autorelease];
    }];
    [self.service executeWithCompletion:^(NSArray *result, NSError *error) {
        MyViewController *me = [zeroWeakRef target];
        if (!me) {
            DULog(@"dodged a bullet");
        }
        if (!error) {
            me.data = result;  
        }
    }];
}
于 2012-06-06T10:14:22.867 に答える
0

回避しようとしている実際の保持サイクルの問題はありますか? 完了selfするまで単純に保持してはならない理由はありますか? -executeWithCompletion:完成しない可能性はありますか?

実際に最終的には (失敗しても) 完了し、呼び出し後にブロックを解放する限り (おそらくプロパティを に設定することによってnil)、保持サイクルは最終的に破られ、すべてがうまくいきます。

于 2012-06-06T08:22:57.030 に答える