【问题标题】:How to use UIAlertController in For loop如何在 For 循环中使用 UIAlertController
【发布时间】:2018-04-09 11:56:14
【问题描述】:

我遇到了一个可能需要重命名的情况,我想使用UIAlertController 来收集新名称。我希望它能够同时进行多项更改(尽管不太可能,但我愿意支持它)。

问题是我需要循环仅在当前UIAlertController 的结果出现时继续,因为它是循环立即继续,当然不能同时出现多个。我整天都被困在这个问题上,需要帮助。

我需要某种使用完成处理程序为下一次循环迭代开绿灯的方法。

这是一个简化版的问题,changeNames函数在UIViewController中。

var names = ["Bob","Kate"]

func changeNames(){
    for name in names {
        let alert = UIAlertController(title: "Rename \(name)",
                                      message: "What would you like to call \(name)?",
                                      preferredStyle: .alert)
        alert.addTextField(configurationHandler: { (textField) in
            textField.text = name
        })
        alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert] (_) in
            print("User changed \(name) to \(alert!.textFields![0].text)")
            //Don't continue the loop until now
        }))
        self.present(alert, animated: true)
    }
}

谢谢


几年后重新审视这个问题

这个问题的基本前提是完全有缺陷的,我是从 VBA 开发人员的角度来看的,对异步代码的理解不足。

这种方法有一些问题:

  1. 通过 UIAlertControllers 收集大量信息真的很糟糕的用户体验 - 专用 UI​​ 会更好
  2. for 循环是表达意图的糟糕方式 - 一堆“itemsToChange”会更好;一项的完成可以启动下一项的处理程序,直到堆栈为空

【问题讨论】:

  • 您可以不使用 for 循环,而是递归地遍历名称列表
  • 你为什么使用for循环??
  • 绝对不是这样……你想达到什么目的?为什么这里需要一个 for 循环?
  • @holex 它是 UICollectionView 的一部分,它具有一个可重用的函数,该函数采用一个动作闭包并将其在 for 循环中应用于集合视图中的所有选定项目

标签: ios swift uialertcontroller


【解决方案1】:

异步代码很难循环,我宁愿使用递归:

func showChangeAlerts(for texts: [String]) {
  guard let value = texts.first else { return }

  let alert = UIAlertController(title: "Rename \(value)",
    message: "What would you like to call \(value)?",
    preferredStyle: .alert)
  alert.addTextField(configurationHandler: { (textField
    textField.text = value
  })
  alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert, weak self] (_) in
    let newValue = alert?.textFields![0].text ?? ""
    print("User changed \(value) to \(newValue)")
    self?.showChangeAlerts(for: Array(texts.dropFirst()))
  }))
  self.present(alert, animated: true)
}

你传入一个字符串数组,这个方法将遍历它们,直到所有的都被处理完。

编辑

好的,刚刚看到 Ron Nabuurs 用一个非常相似的解决方案击败了我 :) 主要区别在于我的方法不使用额外的迭代器参数,而是从提供的数组中“消耗”字符串,直到它为空。但原理是一样的。

【讨论】:

  • 我更喜欢这个anwer,因为它更干净:)
  • @RonNabuurs 呵呵,谢谢...我认为无论哪种方式,OP 都有一个很好的解决方案。
  • 功能是一样的,所以如果它看起来很愚蠢但它有效它不是愚蠢的哈哈
  • @dr_barto 这已经实现并且很有魅力,谢谢!
【解决方案2】:

我没有对此进行测试,因为我目前没有 mac。我的 Swift 生锈了,但总体思路就在那里:P。递归是这里要做的事情:

var names = ["Bob","Kate"]

func changeNames(names: [String], iterator: Int = 0){
    if (names.count >= iterator) {
        let alert = UIAlertController(title: "Rename \(names[iterator])",
                                      message: "What would you like to call \(names[iterator])?",
                                      preferredStyle: .alert)
        alert.addTextField(configurationHandler: { (textField) in
            textField.text = names[iterator]
        })
        alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert] (_) in
            print("User changed \(names[iterator]) to \(alert!.textFields![0].text)")
            changeNames(names, iterator + 1)
        }))
        self.present(alert, animated: true)
    }
}  

【讨论】:

  • @dr_barto 的答案用dropFirst() 干净一点
  • 感谢您的建议,非常感谢您抽出宝贵的时间。我已经为 .dropFirst() 功能选择了 dr_barto 的解决方案。
猜你喜欢
  • 1970-01-01
  • 2019-01-06
  • 2014-11-01
  • 2017-05-24
  • 2018-12-14
  • 2012-10-08
  • 2019-09-18
  • 2022-01-26
  • 2015-05-04
相关资源
最近更新 更多