我正在构建一个基于 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在尝试将一个问题叠加到另一个问题时会感到困惑.我想要的是链接的承诺,所以只有当用户选择“是”或“否”(并且后续的“覆盖”或“不覆盖”代码已经执行)才会进行下一次迭代循环发生.基本上,我希望整个序列是顺序的.
考虑到阵列长度不确定,我如何链接这些承诺呢?我觉得好像错过了一些明显的东西.
编辑:下面的答案之一建议递归.这听起来很合理,但如果列表增长很长,我不确定Swift的堆栈(这是在iOS应用程序中)的含义.理想的情况是,如果有一个构造通过链接承诺更自然地做到这一点.
一种方法:创建一个获取剩余对象列表的函数.在那时使用它作为回调.在伪代码中: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不需要用户交互,并且它们都会在几毫秒的时间内解析,因此场景是真实的).
首先注意回调 – 然后 – 在闭包的上下文中发生,因此它不能像预期的那样与任何外部控制流交互.如果我们不想使用递归,我们可能不得不利用其他一些原生功能.
你可能首先使用promises的原因是你(明智地)不想阻止主线程.然后,考虑剥离第二个线程,其唯一目的是协调这些承诺.如果您的库允许明确地等待承诺,那就做一些类似的事情
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 } }