#swift #recursion #uialertcontroller
Вопрос:
У меня есть программа, над которой я работаю, которая берет массив строк, перебирает этот список и создает двоичное дерево в зависимости от того, что пользователь выбирает из сопоставления «голова к голове».
Проблема в том, что я хочу, чтобы программа остановилась и подождала, пока пользователь выберет опцию в контроллере предупреждений, прежде чем продолжить выполнение вложенных рекурсивных функций. Он этого не делает. Он фактически выполняет код без остановки и отображает контроллер предупреждений в конце.
У меня есть одна рекурсивная функция для итерации по массиву, и в каждом параметре у меня есть рекурсивная функция для размещения в том месте двоичного дерева, где я хочу создать узел со строковым именем.
Код вставлен ниже.
func iterate(value: Int){
if unsortedArray.count > value {
addNode(name: unsortedArray[value])
}
}
func addNode(name: String){
if self.root == nil {
self.root = Node(nameValue: name)
} else {
self.addNode(name: name, node: root!)
}
//raises the value of iterator int by one and calls the iterate function again to access the next string in the array
iterator =1
self.iterate(value: iterator)
}
private func addNode(name: String, node: Node){
showPopUp(name: name, node: node)
}
func showPopUp(name: String, node: Node){
//calls an alert dialog using the names of the two string items as the names of the button.
let alert = UIAlertController(title: "Head to Head Comparison", message: "Select which item you prefer", preferredStyle: .alert)
let nameAction = UIAlertAction(title: name, style: .default) { (UIAlertAction) in
self.output.append("(name) was selected over (node.nodeName) rn")
if node.rightChild == nil {
node.rightChild = Node(nameValue: name)
} else {
self.addNode(name: name, node: node.rightChild!)
}
}
let nodeAction = UIAlertAction(title: node.nodeName, style: .default) { (UIAlertAction) in
self.output.append("(node.nodeName) was selected over (name) rn")
if node.leftChild == nil {
node.leftChild = Node(nameValue: name)
} else {
self.addNode(name: name, node: node.leftChild!)
}
}
alert.addAction(nameAction)
alert.addAction(nodeAction)
present(alert, animated: true, completion: nil)
}
Комментарии:
1. «Я хочу, чтобы программа остановилась и подождала, пока пользователь выберет опцию в контроллере предупреждений, прежде чем продолжить выполнение вложенных рекурсивных функций. Это не значит делать это» Ты не можешь. Программы не «останавливаются и не ждут».
2. Вы должны иметь возможность использовать UIAlertController, добавить действие к этому контроллеру предупреждений (UIAlertAction) и использовать необязательный параметр обработчика для выполнения задачи после завершения действия.
Ответ №1:
Я не смог понять, что должен был делать ваш код (вы не предоставили достаточно информации); но вот пример, который показывает вам общий принцип, которому вам нужно подражать. Вы не «повторяетесь»; вы показываете предупреждение и останавливаетесь. Обработчики кнопок в предупреждении затем снова вызывают метод обхода. В моем примере мы просто пересекаем существующее простое двоичное дерево в соответствии с инструкциями пользователя. Перейдите к основанию и сфокусируйте взгляд на doQuery
методе:
enum Dir {
case left
case right
}
class Node<T> where T: CustomStringConvertible {
let value: T
var left: Node?
var right: Node?
unowned var parent: Node?
init(value: T) {
self.value = value
}
func addChild(_ dir:Dir, value: T) {
let child = Node(value:value)
child.parent = self
let kp = dir == .left ? Node.left : Node.right
self[keyPath:kp] = child
}
func child(_ dir:Dir) -> Node<T>? {
let kp = dir == .left ? Node.left : Node.right
return self[keyPath:kp]
}
func path() -> String {
let result = String(describing: self.value)
if let parent = self.parent {
return parent.path() " -> " result
}
return result
}
}
class ViewController: UIViewController {
let graph = Node(value:"top")
var current : Node<String>?
override func viewDidLoad() {
super.viewDidLoad()
graph.addChild(.left, value: "dog")
graph.addChild(.right, value: "cat")
if let dog = graph.child(.left) {
dog.addChild(.left, value: "rover")
dog.addChild(.right, value: "fido")
}
if let cat = graph.child(.right) {
cat.addChild(.left, value: "whiskers")
cat.addChild(.right, value: "frisky")
}
}
@IBAction func doButton (_ sender:Any) {
current = graph
doQuery()
}
private func doQuery() {
guard let currentNode = current,
let left = currentNode.child(.left),
let right = currentNode.child(.right)
else {
announceResult()
return
}
let alert = UIAlertController(title: "Pick One", message: "Which do you prefer?", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: String(left.value), style: .default) { action in
self.current = currentNode.child(.left)
self.doQuery()
})
alert.addAction(UIAlertAction(title: String(right.value), style: .default) { action in
self.current = currentNode.child(.right)
self.doQuery()
})
self.present(alert, animated: true)
}
private func announceResult() {
guard let result = current else { return }
let alert = UIAlertController(title: "Done", message: "You chose (result.path())", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default))
self.present(alert, animated: true)
}
}
Ответ №2:
Я смог понять, в чем была проблема.. Я выталкивал цикл массива строк за пределы контроллера предупреждений, позволяя контроллеру предупреждений всплывать, а затем после выбора переходить к следующему элементу массива. Спасибо всем вам за помощь. ваши комментарии помогли мне туда попасть.