为什么我无法更改模型数组的顺序?

问题描述 投票:0回答:1

我目前正在编写我的第一个 SwiftData 应用程序。

我创建了两个模型:

玩家.swift:

@Model
final class Player {
    @Relationship(inverse: \Game.players) var games: [Game]
    var name: String
    var id: UUID
    
    init(games: [Game] = [], name: String = "", id: UUID = UUID()) {
        self.games = games
        self.name = name
        self.id = id
    }
}

游戏.swift:

@Model
final class Game {
    @Relationship var players: [Player]

    init(players: [Player] = []) {
        self.players = players
    } 
}

如果我使用players变量显示游戏的玩家,顺序总是相同的,但我不知道为什么以及排序描述符是什么。如果想使用.move重新排列顺序,但不起作用。玩家立即向后跳。如果我使用 .append(),播放器总是附加在相同的位置,具体取决于我使用的位置。例如,如果我添加

Player(games: [], name: "Frank", id: UUID())
,它始终附加在第二个位置,而
Player(games: [], name: "Sean", id: UUID())
始终附加在第四个位置。

GameView.swift:

struct GameView: View {
    
    @Bindable var game = Game()
    
    var body: some View {
        NavigationStack {
            Form {
                Section("Spieler") {
                    ForEach(game.players) { player in
                        Text(player.name)
                    }
                    .onMove(perform: move)
                }
            }
            .navigationTitle("Game")
            .navigationBarTitleDisplayMode(.inline)
        }
    }
    
    func move(from source: IndexSet, to destination: Int) {
        game.players.move(fromOffsets: source, toOffset: destination)
    }
}
arrays swift sorting swift-data
1个回答
0
投票

这里的问题是,您移动的不是普通数组的元素,而是移动的是关系数组属性。

所以,据我了解,基本上发生的情况是,当您执行移动并更改数组时,这会触发 SwiftUI 更新视图,这意味着它将访问

players
game
属性。

我在日志中看不到任何痕迹,因此

game
将简单地返回它所拥有的数组以及最初排序的数组。

如果你想这样做并保留这个新订单,你必须有一些属性来保存玩家订单并将其保留在

onMove
中,这当然会变得更加复杂,因为你有多对多的关系。

要向此答案添加一些代码:) 这是一个示例,说明如何使

onMove
以简单的方式工作,但当然这不会持续存在。我仍然认为它有价值,因为它表明
onMove
有效,但不仅仅是当您直接在关系属性上使用它时。

struct GameView: View {
    var game: Game
    @State var players: [Player]

    init(game: Game) {
        self.game = game
        self.players = game.players
    }

    var body: some View {
        NavigationStack {
            Form {
                Section("Spieler") {
                    ForEach(players) { player in
                        Text(player.name)
                    }
                    .onMove(perform: move)
                }
            }
            .navigationTitle("Game")
            .navigationBarTitleDisplayMode(.inline)
        }
    }

    func move(from source: IndexSet, to destination: Int) {
        players.move(fromOffsets: source, toOffset: destination)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.