首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SwiftUI嵌套ForEach会导致意外排序

SwiftUI嵌套ForEach会导致意外排序
EN

Stack Overflow用户
提问于 2020-07-16 08:32:11
回答 1查看 1.6K关注 0票数 5

我以嵌套的方式使用两种ForEach(),一种用于显示节,另一种用于显示列表视图的各个单元格。

我的问题是,来自第一个ForEach的迭代器变量在第二个ForEach中访问它时行为非常奇怪。

在我所附的这个gif中,第一个变量(在下面的代码片段中的ri)有时会在我向上或向下滚动时改变它的值。但是,在第一个ForEach中,这个变量的值总是相同的,正如我们从显示的圆始终正确的部分名称中可以看到的那样。

下面是带有嵌套ForEach语句的代码。但是,正如这里所介绍的,您可能无法复制该bug。虽然可能很迷信,但似乎我的观点越复杂,bug出现的可能性就越大。

代码语言:javascript
复制
        List {
            ForEach(Array(self.game.rounds.indices), id: \.self) { ri in
                Section(header: Text("Round \(ri): \(self.game.rounds[ri])")) {
                    ForEach(Array(self.game.players.indices), id: \.self) { pi in
                        HStack {
                            Text("\(self.game.players[pi])")
                            Text("Round \(ri), Player \(pi)")
                        }
                    }
                }
            }
        }

下面是嵌套ForEach的完整视图,它给我带来了问题:

https://github.com/charelF/carioca/blob/master/unote/GameView.swift

我相当肯定,我所遇到的实际上是SwiftUI中的一个bug。但是我不确定,这种行为可能是预期的行为,或者是某种异步加载单元的行为。

编辑1:

要么我做错了什么,要么@Asperi的答案似乎并没有真正解决问题。这里有一个快速而又肮脏的解决方法,我试图避免id是相同的

代码语言:javascript
复制
        List {
            ForEach([10,11,12,13,14,15,16,17,18,19] /*Array(self.game.rounds.enumerated())*/, id: \.self) { ri in
                Section(header: Text("Round \(ri-10): \(self.game.rounds[ri-10])")) {
                    ForEach(Array(self.game.players.indices), id: \.self) { pi in
                        HStack {
                            Text("ri \(ri), pi \(pi)")
                        }
                    }
                }
            }

id实际上是不一样的,但是行/单元格仍然是混乱的,就像在这个屏幕截图中看到的.

而且,考虑到我需要索引,所以我很难找到一种很好的方法来迭代这两个数组,这样我就可以真正地迭代数组本身。我能想到的唯一解决方案要么是像上面那样难看的解决方案,要么使用.enumerate() (我尝试过,得到了与上面类似的错误),要么将我的数组转换成具有唯一键的字典.

编辑2:

我相信我理解这个问题。然而,我不知道如何解决它。我尝试为RoundPlayer创建自定义结构,而不是以前使用的Int。这意味着我可以按照以下方式编写嵌套的ForEach

代码语言:javascript
复制
        List {
            ForEach(self.game.rounds, id: \.id) { round in
                Section(header: Text("\(round.number): \(round.desc)")) {
                    ForEach(self.game.players, id: \.id) { player in
                        Text("\(player.name), \(round.number)")
                    }
                }
            }
        }

这需要重写Game.swift https://github.com/charelF/carioca/blob/master/unote/Game.swift背后的逻辑。

不幸的是,这并没有解决问题。命令还是搞砸了。尽管我相信我已经理解了这个问题,但我不知道如何解决这个问题。

编辑3:

我在这里尝试了建议的答案(Nested ForEach (and List) in Views give unexpected results) (将外部ForEach中的视图包含在一个组中),但是错误仍然存在。

编辑4:

我终于让它开始工作了,不幸的是,我的解决方案更多的是一个黑客,真的不太干净。解决方案确实和答案一样,所有的单元都需要唯一的标识符。

代码语言:javascript
复制
List {
    ForEach(self.game.rounds) { round in
        Group {
            Section(header: Text("\(round.number): \(round.desc)")) {
                ForEach(self.game.scoreBoard[round]!, id: \.self.id) { sbe in
                    Text("\(round.number) \(sbe.id)")
                    
                }
            }
        }
    }
}

如下面的屏幕截图所示,第7轮以下的4个单元与第8轮以下的4个单元有不同的标识符,如果我正确理解,这就解决了我的问题。

不幸的是,在我的游戏逻辑中,这个解决方案需要一些丑陋的解决方案。https://github.com/charelF/carioca/blob/master/unote/Game.swift

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-07-16 08:44:34

由于行的非唯一标识符,它失败了。它是使用的索引,但在不同的部分重复,因此列表行重用缓存引擎混淆。

在描述的场景中,应该为行中显示的项选择一些唯一的内容,如(划痕)。

代码语言:javascript
复制
ForEach(self.game.rounds) { round in  // make round identifiable
      // ...
        ForEach(self.game.players) { player in // make player identifiable

rounds ids也不应该与player ids重叠。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62930684

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档