首页 > 解决方案 > 将 ObservedObject 传递给嵌套子视图 SwiftUI(SwiftUI 数据流)

问题描述

我试图理解为什么传递 @ObservedObject 变量不适用于嵌套子视图。可以传递数据,但更改仅反映在创建 @ObservedObject 变量的根视图中。更改不会显示在子视图中。查看 Apple 文档(已针对 Xcode beta 5 进行了更新),答案似乎是同时创建环境对象和常规变量,以便从环境对象中获取正确的索引。这是苹果的例子

我的理解是,@ObservedObject 可用于从多个视图引用变量,但如果您希望可以从任何视图访问数据,那么您应该使用环境对象。因此,我相信通过@ObservedObject 应该是可能的。我认为正在发生的问题是,由于 ScreenTwo 将 @Binding 变量传递给 DetailsView,这就是导致问题的原因。为了解决这个问题,我认为你需要继续传递完整的@ObservedObject,但是你又需要某种类型的常规变量来获得正确的索引。

我觉得所有这些都应该更直接。

import SwiftUI
import Combine

struct Sport: Identifiable{
    var id = UUID()
    var name : String
    var isFavorite = false
    var school : String
}

final class SportData: ObservableObject  {
    @Published var store =
        [
            Sport(name: "soccer", isFavorite: false, school: "WPI"),
            Sport(name: "tennis", isFavorite: false, school: "WPI"),
            Sport(name: "swimming", isFavorite: true, school: "WPI"),
            Sport(name: "running", isFavorite: true, school: "RIT"),
    ]
}

struct Testing: View {
    @ObservedObject var sports = SportData()

    var body: some View {
        NavigationView{
            List{
                ForEach($sports.store){ sport in
                    NavigationLink(destination: ScreenTwo(sport: sport)){
                        HStack {
                            Text(sport.value.name)
                            Spacer()
                            Text(sport.value.isFavorite.description)
                        }
                    }
                }
            }
        }.navigationBarTitle("Settings")
    }
}

struct ScreenTwo : View{
    @Binding var sport : Sport

    var body: some View{
        NavigationLink(destination: DetailsView(sport: $sport)){
            Text(sport.isFavorite.description)
        }
    }
}

struct DetailsView: View {
    @Binding var sport : Sport

    var body: some View {
        Button(action: {
            self.sport.isFavorite.toggle()
            self.sport.name = "Ricky"
        }) {
            Text(sport.isFavorite.description)
            Text(sport.name)
        }
    }
}



#if DEBUG
struct Testing_Previews: PreviewProvider {
    static var previews: some View {
        Testing()
    }
}
#endif

标签: xcodenestedobservableswiftui

解决方案


对于ObservableObject配对ObservedObject使视图刷新,因此要解决有问题的任务,我建议采用以下方法:

演示

ObservingObject/ObjservedObject 模式的使用

代码

import SwiftUI
import Combine

class Sport: ObservableObject, Hashable, Identifiable {

    static func == (lhs: Sport, rhs: Sport) -> Bool {
        lhs.name == rhs.name && lhs.isFavorite == rhs.isFavorite && lhs.school == rhs.school
    }

    func hash(into hasher: inout Hasher) {
        hasher.combine(name)
        hasher.combine(isFavorite)
        hasher.combine(school)
    }

    @Published var name : String
    @Published var isFavorite = false
    @Published var school : String

    init(name: String, isFavorite: Bool, school: String) {
        self.name = name
        self.isFavorite = isFavorite
        self.school = school
    }
}

final class SportData: ObservableObject  {
    @Published var store =
        [
            Sport(name: "soccer", isFavorite: false, school: "WPI"),
            Sport(name: "tennis", isFavorite: false, school: "WPI"),
            Sport(name: "swimming", isFavorite: true, school: "WPI"),
            Sport(name: "running", isFavorite: true, school: "RIT"),
    ]
}

struct TestingObservedObject: View {
    @ObservedObject var sports = SportData()

    var body: some View {
        NavigationView{
            List{
                ForEach(sports.store){ sport in
                    NavigationLink(destination: ScreenTwo(sport: sport)) {
                        HStack {
                            Text("\(sport.name)")
                            Spacer()
                            Text(sport.isFavorite.description)
                        }
                    }
                    .onReceive(sport.$isFavorite) { _ in self.sports.objectWillChange.send() }
                }
            }
        }.navigationBarTitle("Settings")
    }
}

struct ScreenTwo : View{
    @ObservedObject var sport : Sport

    var body: some View{
        NavigationLink(destination: DetailsView(sport: sport)){
            Text(sport.isFavorite.description)
        }
    }
}

struct DetailsView: View {
    @ObservedObject var sport : Sport

    var body: some View {
        Button(action: {
            self.sport.isFavorite.toggle()
            self.sport.name = "Ricky"
        }) {
            Text(sport.isFavorite.description)
            Text(sport.name)
        }
    }
}



#if DEBUG
struct Testing_Previews: PreviewProvider {
    static var previews: some View {
        TestingObservedObject()
    }
}
#endif

推荐阅读