如果按下按钮,则仅在 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
循环,因为您只需要等待用户输入。一旦您收到用户输入,您就将其存储起来并转到下一个问题,这就是您最终将循环遍历所有问题的方式。希望它有意义
我有以下设置:
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
循环,因为您只需要等待用户输入。一旦您收到用户输入,您就将其存储起来并转到下一个问题,这就是您最终将循环遍历所有问题的方式。希望它有意义