防止 SwiftUI 中的数组重新洗牌

Posted

技术标签:

【中文标题】防止 SwiftUI 中的数组重新洗牌【英文标题】:Prevent array re-shuffle in SwiftUI 【发布时间】:2021-09-24 02:49:02 【问题描述】:

我一直在 SwiftUI 中创建一个问答应用程序,并一直在尝试为随机排列的答案创建一个数组。最初我将数组改组如下:

var answers = ["answerOne", "answerTwo", "answerThree", "answerfour"].shuffled

这个数组以ForEach 循环的形式显示在屏幕上,该循环在如下所示的列中提供了选项(可以选择的答案):

Question:
Answer One
Answer Two
Answer Three
Answer Four

(Check answer button)

虽然效果很好,但当按下检查答案按钮时,答案数组将再次随机排列为不同的顺序,如下所示,这是不可取的。

Question:
Answer Three
Answer One
Answer Two
Answer Four

(Next question button)

有没有一种方法可以让我只在按下“下一个问题按钮”而不是“检查答案按钮”时才对数组进行洗牌?

以下是我尝试作为解决方案的代码,但它似乎没有奏效,我非常感谢任何人的任何意见或想法!

Button(action: 
    if(oddEven % 2 == 0) 
        checkNextText = "Next"
        oddEven += 1
     else 
        checkNextText = "Check"
        answers.shuffled()
        oddEven += 1
    

注意:checkNextText 是屏幕底部按钮的文本,oddEven 是一个 Int 变量,用于确定按钮应该读取 check 还是 next。

最小复制代码:

import SwiftUI

struct ContentView: View 
    
    @State var oddEven = 0
    @State var checkNextText = "Check"
    
    var body: some View 

        var orderedAnswers = [                    
        "answerOne",
        "answerTwo",
        "answerThree",
        "answerFour"                    
        ].shuffled()

        Text("Question One")

        ForEach(0..<4)  number in
                    Button(action: , label: 
                    Text(orderedAnswers[number])
                )
        

        Button(action: 
            if(oddEven % 2 == 0) 
                checkNextText = "Next"
                oddEven += 1            
             else 
                checkNextText = "Check"
                oddEven += 1
            
        , label:                         
            Text(checkNextText)
        )    
    

【问题讨论】:

您能否包含一个minimal reproducible example,以便他人可以复制并粘贴到 Xcode 中以查看您目前拥有的内容? 嗨!没问题,我会在编辑中添加一个。 body 会在您的视图中的某些内容发生变化时刷新...所以由于var orderedAnswers = [body 内,它会意外地重新洗牌。把它移到外面。 感谢@aheze 的回答。唯一的问题是我提供的代码是实际代码的一个非常精简的版本,将它移到体外需要大量的重构。有没有其他方法可以实现洗牌,而不必将数组移到体外? @imjonu 不幸的是没有。通常你希望你的所有变量都在身体之外,否则你会遇到奇怪的副作用。 【参考方案1】:

正如其他人所建议的那样,惯用的方法是将数组存储在您的视图中,而不是作为body 属性中的局部变量,因为正如已经指出的那样,每次body 是调用(可能不止一次发生)。

但是,如果由于各种原因无法将代码提取到正文之外,另一种方法是使用仅设置一次的 @State 属性:

struct ContentView: View 
    @State orderedAnswers: [String]?

,仅当状态未设置时才进行计算:

var body: some View 
    var orderedAnswers = self.orderedAnswers ?? [                    
        "answerOne",
        "answerTwo",
        "answerThree",
        "answerFour"                    
        ].shuffled()

【讨论】:

以上是关于防止 SwiftUI 中的数组重新洗牌的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI 中的 List 是不是复用类似于 UITableView 的单元格?

SwiftUI如何防止视图重新加载整个身体

如何在 Touch Down 实现时防止 SwiftUI 上的重新触发

如何防止 SwiftUI 像使用 @StateObject 一样重新初始化我的包装属性?

使用本地 JSON 中的键:值更改按钮/标签文本 - SwiftUI

按返回键“不”关闭软件键盘 - SwiftUI