2

まず第一に (この質問はメモリ管理に関係しているため)、私は ARC で実行していると言わざるを得ません。

MyProcess オブジェクトの配列を含むオブジェクト (MyObject) があります。MyObject は、特定の時点で、新しい MyProcess を作成し、それを配列に追加し、ブロックの形式で完了ハンドラーを提供し、プロセスに開始を指示します。

MyProcess* newProcess = [MyProcess new];

[allProcessesArray addObject: newProcess];

newProcess.completionBlock = ^(MyProcess* process){
    [allProcessesArray removeObject: process];
    // Other things are done here
};

[newProcess start];

ここで、MyProcess 側では、start が呼び出されると、MyProcess は内部的に threadedStart (バックグラウンド スレッドで実行される) を呼び出します。これは作業を実行し、終了時にブロックを呼び出します。

- (void)threadedStart
{
    // Do something

    dispatch_async(dispatch_get_main_queue(), ^{ self.completionBlock(self); });
}

完了ブロックは、次のように MyProcess のインターフェイスでプロパティとして定義されます。

typedef void(^MyCallbackBlock)(MyProcess* process);
@property (strong) MyCallbackBlock completionBlock;

現在、MyProcess は allProcessesArray によって存続期間中のみ維持されます。これは、その配列がプロセスへの参照を持つ唯一のオブジェクトであるためです。完了ブロックで配列からプロセスを削除すると、プロセスはすぐにロック解除されると思います。次に、プロセスにはブロック自体が含まれているため、ブロックがまだ実行されている間にブロックもロック解除されます。

これにより問題が発生することが予想されますが、このコードをテストしたところ、ブロックは最後まで問題なく動作しました。ここで、2 つの選択肢があります。私の推論が間違っていて、このコードは完全に安全であるか、または私が正しい (または少なくとも部分的に正しい) が、時々しか機能しないため、これは安全ではありません。

基本的に、私の質問は: コールバック ブロックへのこのアプローチは安全ですか? そうでない場合は、別のことを提案できますか?

4

1 に答える 1

1

ブロック プロパティの場合、copyではなく である必要がありstrongます。ブロックは常にコピーする必要があります。

@property (copy) MyCallbackBlock completionBlock;

ブロックを実行すると問題が発生するかどうかは、実行されるコードと、使用する変数がどのように定義されているかによって異なります。

ブロックの内側では、ウェイmyProcessはブロックの外側で定義されているため、ブロックの内側に保持されます。したがって、配列から削除しても、ブロックの最後まで保持されます。

技術的には、これは保持サイクルの一種として分類できますが、その構造によりうまく機能します。

ブロック自体は、実行中に「割り当て解除」することはできません。


更新されたコードの場合、インスタンスはブロックへの呼び出しによって保持されます (パラメーターとして提供されるため)。繰り返しますが、インスタンスはブロックの実行が終了するまで保持されます。

于 2013-06-23T11:13:51.823 に答える