如果按下按钮,则仅在 for 循环内继续

Only continue within for loop if button was pressed

我有以下设置: Classes A 和 B。Class A 生成形式为 [["SettingCategory"]] 的设置数组。 Class B 控制视图并包含 2 个按钮和一个提交按钮。 我使用 for-in 循环遍历设置数组。用户可以为每个设置选择 opt1/opt2,然后提交选择。然后他会被问到第二个、第三个……设置。 我在等待用户提交他的选择时遇到了麻烦。我的 for 循环只遍历数组的所有元素,不允许任何交互。我不需要代码,我真的很感激如何正确执行此操作的基本概念。

这里是一些简化的代码:

class A{
   var settingCategories = [["Sound", "loud", "soft"], ["Brightness", "dark", "bright"]]
   
   for setting in settingCategories{
      if setting[0] == "Sound"{
         classB.showTheCategory(opt1: setting[1], opt2: setting[2])

         // here I want to wait for the user to choose "loud" or "soft" and then submit it.
         // I only want to continue, when the user submitted his choice!
         // my loop just iterates through all elements of the array and does not detect 
         // button taps.
      }
   }
}

class B{ // ViewController
   showTheCategory(opt1: String, opt2: String){
      // this ONLY generates and shows the buttons: opt1, opt2 and SUBMIT
   }
   detectButtonPressed(){
      // here I detect what button was pressed
   }
}

由于我的架构,我无法在 showTheCategory 函数中检测到按下的按钮。我尝试在 class A 中使用 while 循环,但我最终得到了一个无限循环。而且我不想使用计时器,因为我不知道用户制作和输入需要多长时间。我查找了通知,但我的 for 循环不等待属性更改,它只是快速遍历它们。

您没有检测到“在 showTheCategory 函数中”按下按钮。 Swift 不是这样的。在循环内您需要做的就是添加按钮(我假设 showTheCategory)。

然后,在 showTheCategory 中,您可以为每个按钮分配一个处理程序。

/// enum for listing possible button types
enum ButtonType {
    case sound
    case loud
    case soft
    case brightness
    case dark
    case bright
}

class A {
   var settingCategories = [["Sound", "loud", "soft"], ["Brightness", "dark", "bright"]]
   
   for category in settingCategories {

       /// loop again
       for setting in category {

            /// check each individual setting
            if setting == "Sound" {
                classB.showTheCategory(buttonType: .sound, opt1: setting[1], opt2: setting[2])
            }
        }
    }
}

class B {
    func showTheCategory(buttonType: ButtonType, opt1: String, opt2: String) {
        // this ONLY generates and shows the buttons: opt1, opt2 and SUBMIT
        let button = UIButton(frame: CGRect(x: 100, y: 100, width: 100, height: 50))
        button.setTitle(opt1, for: .normal)
        
        switch buttonType {
        case .sound:
            button.addTarget(self, action: #selector(detectButtonPressed), for: .touchUpInside)
        case .loud:
            button.addTarget(self, action: #selector(detectLoudButtonPressed), for: .touchUpInside)
        case .soft:
            button.addTarget(self, action: #selector(detectSoftButtonPressed), for: .touchUpInside)
        case .brightness:
            button.addTarget(self, action: #selector(detectBrightnessButtonPressed), for: .touchUpInside)
        case .dark:
            button.addTarget(self, action: #selector(detectDarkButtonPressed), for: .touchUpInside)
        case .bright:
            button.addTarget(self, action: #selector(detectBrightButtonPressed), for: .touchUpInside)
        }
        self.view.addSubview(button)
    }
    
    @objc detectSoundButtonPressed(sender: UIButton!) {
    }
    @objc detectLoudButtonPressed(sender: UIButton!) {
    }
    @objc detectSoftButtonPressed(sender: UIButton!) {
    }
    @objc detectBrightnessButtonPressed(sender: UIButton!) {
    }
    @objc detectDarkButtonPressed(sender: UIButton!) {
    }
    @objc detectBrightButtonPressed(sender: UIButton!) {
    }
}

我绝不是专家,但我想我可以有一个解决方案,所以你可以试试这个:

因此,假设您的 showCategory 和 detectButtonPressed 函数都正常工作,一个选项可能是使用 DispatchGroup 和一些异步代码来完成这项工作。基本上做这样的事情。

class A{
   var settingCategories = [["Sound", "loud", "soft"], ["Brightness", "dark", "bright"]]
   let dispatcher = DispatchGroup()
   let dispatchQueue = DispatchQueue(label: "Doesn't really matter", qos: .background)
   dispatchQueue.async{
      for setting in self.settingCategories{
         if setting[0] == "Sound"{
            classB.showTheCategory(opt1: setting[1], opt2: setting[2], dispatcher: dispatcher)
            self.dispatcher.wait()
         }
      }
   }
}

class B{ // ViewController
   var dispatcherB = DispatchGroup()
   showTheCategory(opt1: String, opt2: String, dispatcher: DispatchGroup){
      // Here you should change the dispatcherB

      dispatcherB = dispatcher
      dispatcher.enter()
      DispatchQueue.main.async{
         // display buttons here
      }
   }
   detectButtonPressed(){
      // when the button is pressed do this
      dispatcherB.leave()
   }
}

如果您不熟悉调度组和队列,组基本上是一种在执行其他操作之前等待一部分代码 运行 的方法,在这种情况下,队列用于 运行 您想要同时 运行 的部分代码。例如,如果您想显示一个视图并检测用户交互,同时 运行 设置您的 for 循环,它必须在每个设置处停止。如果您在更改视图之前而不是同时 运行 for 循环,您的屏幕将冻结并且用户将无法执行任何操作。这就是调度组和队列的组合应该起作用的原因。

我想知道的另一件事是你为什么 运行 在两个不同的 class 中使用它。如果您 运行 将所有内容都放在同一个 class 上,您实际上可以在 detectButtonPressed() 中更改显示的按钮,这会使事情变得容易得多。不管怎样希望对你有帮助哈哈哈

这是一些伪代码

// create an array to hold your answers
var answers: [Answer] = []()
// create an array to hold your questions
var questions: [Question] 
var currentQuestion: Question {
    didSet {
       // every time this property updates show the new question
       self.showQuestion(self.currentQuestion)
    }
}

init(questions: [Question]) {
   // store the questions
   self.questions = questions
   // pop your first questions from the list and assign it as the current question
   // this would also trigger its didSet method to display the question
   self.currentQuestion = self.questions.pop()
}

func showQuestion(_ question: Question) {
   // display question on screen
   questionLabel.text = question.text
   firstButton.title = question.firstOption
   secondButton.title = question.secondOption
}

func onButtonClick(sender: UIButton) {
   // user selected an answer, you can now store it and move to your next question. Here is how you can do it
   
   // create your answer and store it
   let answer = Answer(currentQuestion.text, answer: sender.title)
   self.answers.append(answer)
   // check if there is more questions in the list
   if self.questions.count > 0 {
      there is more questions so take one and show it the user
      self.currentQuestion = self.questions.pop()
   } else {
     // you have finished with all questions
     // you have successfully looped through all questions
     // and all user answers are now stored in your answers array
     // do with your answers whatever you need to. You're now done with asking questions :)
   }
}

这展示了您可以用来实现您所寻找的目标的逻辑。无需实现 for 循环,因为您只需要等待用户输入。一旦您收到用户输入,您就将其存储起来并转到下一个问题,这就是您最终将循环遍历所有问题的方式。希望它有意义