Swift: Остановка вложенной рекурсивной функции с помощью контроллера предупреждений для ввода пользователем

#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:

Я смог понять, в чем была проблема.. Я выталкивал цикл массива строк за пределы контроллера предупреждений, позволяя контроллеру предупреждений всплывать, а затем после выбора переходить к следующему элементу массива. Спасибо всем вам за помощь. ваши комментарии помогли мне туда попасть.