4

我正在构建一个基于 Swift 的 iOS 应用程序,它使用PromiseKit来处理 Promise(尽管如果它使我的问题更容易解决,我愿意切换 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 的下一次迭代循环发生。本质上,我希望整个序列是连续的。

考虑到数组的长度不确定,我该如何链接这些承诺?我觉得好像我错过了一些明显的东西。

编辑:以下答案之一建议递归。这听起来很合理,虽然我不确定如果列表变长对 Swift 的堆栈(这是在 iOS 应用程序内部)的影响。理想的情况是,如果有一个结构可以通过链接到 Promise 来更自然地做到这一点。

4

1 回答 1

0

一种方法:创建一个函数来获取剩余对象的列表。将其用作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 the then)发生在闭包的上下文中,因此它无法与任何外部控制流进行交互,正如预期的那样。如果我们不想使用递归,我们可能不得不利用其他一些原生特性。

您首先使用 Promise 的原因大概是您(明智地)不想阻塞主线程。然后考虑分离第二​​个线程,其唯一目的是编排这些承诺。如果您的库允许显式等待一个承诺,只需执行类似的操作

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 回答