4

PromiseKitを使用して Promise を処理する Swift ベースの iOS アプリケーションを構築しています (問題の解決が容易になる場合は、Promise ライブラリの切り替えを受け入れます)。ファイルの上書きに関する質問を処理するために設計されたコードのセクションがあります。

おおよそ次のようなコードがあります。

let fileList = [list, of, files, could, be, any, length, ...]

for file in fileList {
  if(fileAlreadyExists) {
    let overwrite = Promise<Bool> { fulfill, reject in
      let alert = UIAlertController(message: "Overwrite the file?")
      alert.addAction(UIAlertAction(title: "Yes", handler: { action in 
        fulfill(true)
      }
      alert.addAction(UIAlertAction(title: "No", handler: { action in 
        fulfill(false)
      }
    } else {
      fulfill(true)
    }
  }

  overwrite.then { result -> Promise<Void> in
    Promise<Void> { fulfill, reject in
      if(result) {
        // Overwrite the file
      } else {
        // Don't overwrite the file
      }
  }
}

ただし、これは望ましい効果がありません。for ループは、リストを反復処理するのと同じ速さで「完了」します。つまり、UIAlertController は、ある質問を別の質問に重ねようとして混乱します。私が望むのは、ユーザーが「はい」または「いいえ」を選択した場合 (および後続の「上書きする」または「上書きしない」コードが実行された場合) にのみ、 for の次の反復を実行するように、約束を連鎖させることです。ループが発生します。基本的に、シーケンス全体をシーケンシャルにしたいのです。

配列の長さが不定であることを考慮して、これらの約束を連鎖させるにはどうすればよいですか? 明らかな何かが欠けているように感じます。

編集:以下の回答の1つは再帰を示唆しています。リストが長くなった場合に Swift のスタック (これは iOS アプリ内にあります) への影響についてはわかりませんが、それは妥当に思えます。promise にチェーンすることによって、これをより自然に行うための構造があれば理想的です。

4

1 に答える 1

0

1 つの方法: 残っているオブジェクトのリストを取得する関数を作成します。それを のコールバックとして使用しますthen。擬似コード:

function promptOverwrite(objects) {
    if (objects is empty)
        return
    let overwrite = [...]  // same as your code
    overwrite.then {
        do positive or negative action
        // Recur on the rest of the objects
        promptOverwrite(objects[1:])
    }
}

何万もの promise がある場合にコール スタックを吹き飛ばさないようにするために、再帰なしでこれを行うことにも関心があるかもしれません。(promise はユーザーの操作を必要とせず、シナリオが現実的であるように、すべて数ミリ秒のオーダーで解決されると仮定します)。

最初に、コールバック — in — はthenクロージャのコンテキストで発生することに注意してください。そのため、予想どおり、外側の制御フローと対話することはできません。再帰を使用したくない場合は、おそらく他のネイティブ機能を利用する必要があります。

そもそもプロミスを使用している理由は、おそらく、メイン スレッドを (賢明に) ブロックしたくないからです。次に、これらの約束を調整することを唯一の目的とする 2 番目のスレッドをスピンオフすることを考えてみましょう。ライブラリが約束を明示的に待つことを許可している場合は、次のようにしてください

function promptOverwrite(objects) {
    spawn an NSThread with target _promptOverwriteInternal(objects)
}
function _promptOverwriteInternal(objects) {
    for obj in objects {
        let overwrite = [...]  // same as your code
        overwrite.then(...)    // same as your code
        overwrite.awaitCompletion()
    }
}

promises ライブラリでこれができない場合は、ロックを使用して回避できます。

function _promptOverwriteInternal(objects) {
    semaphore = createSemaphore(0)
    for obj in objects {
        let overwrite = [...]  // same as your code
        overwrite.then(...)    // same as your code
        overwrite.always {
            semaphore.release(1)
        }
        semaphore.acquire(1)  // wait for completion
    }
}
于 2016-06-20T00:20:01.700 に答える