遍历 NSSet - SwiftUI 2.0

Iterate over a NSSet - SwiftUI 2.0

我开始查看 CoreData 并有两个实体。这些形成了 Player 之间的多对多关系:

和团队:

我正在尝试使用列表中的 ForEach 遍历团队的球员,但我似乎无法让它工作。我一直在尝试的代码如下。我尝试的任何其他解决方案都会出现错误,例如 'Value of type NSObject has no member name'

struct PlayersView: View{
    var team: Team
    
    var body: some View{
        NavigationView{
            List{
                ForEach(Array(team.people! as Set), id: \.self){ player in
                    Text("\(player.name)" ) //Error on this line
                    
                }
            }
        }
    }
}

有什么想法吗?我想我需要将播放器类型改回播放器对象,但我不确定

尝试以下操作(使用 Xcode 12.1 / iOS 14.1 编译)

ForEach(Array(team.people as? Set<Player> ?? []), id: \.self){ player in
    Text("\(player.name ?? "")" )
}

注意:尽量避免强制展开可选项,这通常会导致 运行-time 崩溃。

虽然 that @Asperi 建议有效,但存在一个问题。 ForEach 在显示由 NSSet 支持的值集合时被剥夺了反应性更新。如果 people 发生变化,ForEach 将无法获取该变化并立即自行刷新。

这是因为 NSSet 是一个 class,而 SwiftUI 只能反应性地更新结构属性,如前所述

我相信更好的架构是使用获取请求来获取与给定团队关联的所有玩家。该获取请求必须在视图的初始化方法中进行配置,其中 NSPredicate 指定我们需要特定球队的球员。如果您有 多对多 关系,请在 NSPredicate.

中使用 ANY 运算符
struct PlayersView: View {
    let team: Team
    
    @FetchRequest private var people: FetchedResults<Player>
    
    init(team: Team) {
        self.team = team
        
        _people = FetchRequest(
            entity: Player.entity(),
            sortDescriptors: [NSSortDescriptor(keyPath: \Player.name, ascending: true)],
            predicate: NSPredicate(format: "team == %@", team)
        )
    }
    
    var body: some View {
        NavigationView {
            List {
                ForEach(people) { player in
                    Text("\(player.name ?? "")")
                }
            }
        }
    }
}

现在我们可以将获取请求的结果直接插入 ForEach,而不必进行任何类型转换。更好的是,SwiftUI 现在可以根据它注意到的变化自动更新 ForEach 的内容。