2

他の人がこの問題をどのように解決したかを調べるためにたくさん検索しましたが、残念ながら、この特定の質問に対する答えは見つかりませんでした. よろしくお願いします。

要約は次のとおりです。私のクラスには、method1 と method2 という 2 つのメソッドがあります。method1 内で非同期関数を呼び出す必要があります。その後、コードは実行を続け、method2 に到達します。しかし、メソッド 2 では、その非同期呼び出しの結果をメソッド 1 で使用する必要がある場合があるため、メソッド 2 の残りの部分に進む前に、メソッド 1 の非同期呼び出しが終了していることを確認する必要があります。

1 つはセマフォを使用する方法で、もう 1 つは完了ブロックを使用する方法です。しかし、私はこれを最も一般的な方法で行いたいと考えています。これは、実行を続行する前に、method1 の非同期呼び出しが完了するまで待機する必要がある method2 と同様の他のメソッドがあるためです。また、同じ理由で、単純に method2 自体の内部で async 関数を呼び出して、残りの method2 をその完了ブロックに入れることはできません。

これが私がやろうとしていることの大まかな考えです。誰かがこの疑似コードに CompletionBlocks を追加してくれるとありがたいです。そうすれば、物事がどのように機能するかを明確に理解できます。ところで、method1 と method2 (およびこのクラスの他のすべてのメソッド) は同じスレッド上にあります (メイン スレッドではありません)。

@implementation someClass

-(void)method1 {
    for (each item in the ivar array) {
        if (condition C is met on that item) {
            some_independent_async_call(item, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(int result, int *someArray) {
                if (result > 0) {
                    // The async call worked correctly, we will need someArray
                }
                else {
                    // We didn't get someArray that we wanted.
                }
            });
        }
    }
}

-(void)method2 {
    // Select one item in the ivar array based on some criteria.
    if (condition C is met on that item) {
        // Wait for some_independent_async_call() in method1 to complete.
        // Then use someArray in the rest of the code.
    }
    else {
        // Simply continue the rest of the code. 
    }
}

@end

更新: 非同期呼び出しが完了したらセマフォにシグナルを送ることができ、method2 で同じセマフォを待つことができることはわかっていますが、代わりに完了ブロックを使用したいと考えています。このクラスの method2。このコードを機能させるのに問題があるので、誰かがこのコードに完了ブロックを追加してもらえますか?

4

2 に答える 2

1

私が問題を正しく理解していれば、「アイテム」のリストと 1 つの非同期タスクが得られます。タスクはパラメーターitemを取り、いくつかの「結果」(Int の配列) を計算します。

ここで、「アイテム」ごとにブール値が評価され、このアイテムを引数としてタスクを開始するかどうかが決定されます。

各タスク ( your some_independent_async_call) が完了すると、継続を呼び出します (対応する完了したタスクの結果を使用する可能性があります)。

ディスパッチ グループ、完了ハンドラ、NSOperations などを使用してこれを実装することは確かに可能です。ただし、特にエラーを処理し、必要に応じてタスクをキャンセルする手段を実装する場合は特に、これは非常に複雑でエラーが発生しやすくなります。しかし、これは「Futures」を使用すると信じられないほど簡単になるため、この解決策を提案します。

「先物」は標準の Swift ライブラリには含まれていないことに注意してください。ただし、利用可能なサードパーティのライブラリがいくつかあります。ここでは、「Scala ライクな」 futuresを使用します。これは、「Promises」でも同様の方法で実装できることに注意してください。wiki Futures and Promisesも参照してください。

先物を使用すると、タスクには次のシグネチャがあります。

typealias TaskType = (Item) -> Future<SomeResult>

future は、基礎となる非同期タスクによって後で計算される値の「プレースホルダー」です。タスクが失敗し、値の代わりにエラーが返される場合もあります。つまり、未来は結果またはエラーのいずれかで最終的に完了します。

タスクを次のようにします。

func task(item: Item) -> Future<SomeResult> {
    let promise = Promise<SomeResult>()
    fetchSomeResult(item.url) { (result, error) in
        if let result = result {
            promise.fulfill(result)
        } else {
            promise.reject(error!)
        }
    }
    return promise.future!
}

配列をフィルタリングして、タスクを開始する実際の「アイテム」を取得する方が簡単なようです。

let activeItems = items.filter { $0.foo == something }

先物の配列を取得します。

let futures = activeItems.map { task($0) } 

上記のステートメントは非同期タスクを開始し、それぞれに対応する項目があり、型が であるフューチャーの配列を返し[Future<SomeResult>]ます。現時点では、先物はまだ完成していません。これは、基礎となるタスクが終了したときに、最終的に各フューチャーで発生します。

ここで、タスクが成功したときに呼び出される各フューチャに継続を追加し、発生時に呼び出されるエラー ハンドラも追加します。

futures.forEach { future in
    future.map { result in
        // This will be entered for each task, once it 
        // finished successfully.
        // Handle result (should be your array of ints)
        // This is where you implement the "method2" part
        // but for each item separately.
        // Note: if you need the "item" as well, use a
        // task which returns a tuple:
        // task(item: Item) -> Future<(Item, SomeResult)>
    }.onFailure { error in
       // handle error. This is an error returned from the task.
    }
}
于 2016-05-03T19:57:49.340 に答える
1

コードに基づいて、非同期ディスパッチを制御しているように見えます。

some_independent_async_calluseの代わりにdispatch_sync、指定されたブロックが完了するまで現在のスレッドでの実行をブロックします

Grand Central Dispatch で dispatch_sync を使用する

ただし、非同期呼び出しを制御できず、実際にオブジェクトのメソッドを呼び出している場合、オブジェクトはdispatch_async;を呼び出します。あなたが述べたように、完了ブロック、コールバックパターン、またはセマフォを使用する選択肢はありません

于 2016-05-03T17:27:56.530 に答える