How to use UIAlertController in For loop

徘徊边缘 提交于 2019-12-13 09:54:43

问题


I've got a scenario where something may need to be renamed and I'd like to use UIAlertController to collect the new name. I'd like this to be robust for several changes at once (although it's unlikely, I'd like to support it).

The issue is that I need the loop to continue only when the results of the current UIAlertController are in, as it is, the loop continues immediately and of course can't present more than one at once. I've been stuck on this all day and need help.

I need some kind of method that uses the completion hander to give the green light to the next loop iteration.

This is a simplified version of the problem, the changeNames func is in a 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)
    }
}

Thanks


回答1:


Looping is hard with asynchronous code, I'd rather go with recursion:

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)
}

You pass in an array of strings, and this method will work through them until all have been processed.

EDIT

Ok, just saw that Ron Nabuurs beat me with a very similar solution :) The main difference is that my method doesn't use the additional iterator parameter, but "consumes" strings from the provided array until it's empty. But the principle is the same.




回答2:


I have not tested this because I don't have a mac at the moment. And my Swift is rusty, but the general Idea is there :P. Recursion is the thing to do here:

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)
    }
}  


来源:https://stackoverflow.com/questions/49732371/how-to-use-uialertcontroller-in-for-loop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!