通过按钮中的分配更新EnvironmentObject变量

时间:2019-08-09 22:29:54

标签: swiftui

我有一个一次性项目,试图使自己熟悉SwiftUI。本质上,我有各种类型的苹果,可以通过EnvironmentObject变量来使用。该项目与我经历过的Landmarks教程相似,但我正在扩展诸如步进器和按钮等对象的使用。

我当前正试图拥有一个按钮,当按下该按钮时,保存某种苹果的UUID,并将其发送回原始视图。它不起作用,我不确定为什么。似乎environmentObject分配存在一个问题,没有逃避action:的闭包。设置了打印语句和“文本”视图以在某些点显示变量的值。尽管它似乎在闭包中设置了变量,但它并没有逃脱闭包,并且从未真正更新过变量。

func scene(
  _ scene: UIScene,
  willConnectTo session: UISceneSession,
  options connectionOptions: UIScene.ConnectionOptions
) {
  if let windowScene = scene as? UIWindowScene {
    let window = UIWindow(windowScene: windowScene)
    window.rootViewController = UIHostingController(rootView: ContentView().environmentObject(UserData()))
    self.window = window
    window.makeKeyAndVisible()
  }
}

struct AppleData: Codable, Hashable, Identifiable {
  let id: UUID
  var appleType: String
  var numberOfBaskets: Int
  var numberOfApplesPerBasket: [Int]
  var fresh: Bool

  static let `default` = Self(id: UUID(uuidString: "71190FD1-C8E0-4A65-996E-9CE84D200FBA")!,
                              appleType: "appleType",
                              numberOfBaskets: 1,
                              numberOfApplesPerBasket: [0],
                              fresh: true)  // for purposes of automatic preview

  func image(forSize size: Int) -> Image {
    ImageStore.shared.image(name: appleType, size: size)
  }
}

let appleData: [AppleData] = load("apples.json")
var appleUUID: UUID?

func load<T: Decodable>(_ filename: String, as type: T.Type = T.self) -> T {
  ... // Code Omitted For Brevity
}

final class UserData: ObservableObject {
  let willChange = PassthroughSubject<UserData, Never>()

  var apples = appleData {
    didSet {
      willChange.send(self)
    }
  }
  var appleId = appleUUID {
    didSet {
      willChange.send(self)
    }
  }
}

struct ContentView : View {
  @EnvironmentObject private var userData: UserData

  var body: some View {
  NavigationView {
    List {
      ForEach(appleData) { apple in
        NavigationLink(
          destination: AppleDetailHost(apple: apple).environmentObject(self.userData)
        ) {
          Text(verbatim: apple.appleType)
        }
      }
      Text("self.userData.appleId:  \(self.userData.appleId?.uuidString ?? "Nil")")
    }
    ... // Code Omitted For Brevity
  }
}

struct AppleDetail : View {
  @EnvironmentObject var userData: UserData
  @State private var basketIndex: Int = 0

  var apple: AppleData

  var totalApples: Int {
    apple.numberOfApplesPerBasket.reduce(0, +)
  }

  var body: some View {
    VStack {
      ... // Code Omitted For Brevity
    }

    Button(action: {
      print("self.userData.appleId: \(self.userData.appleId?.uuidString ?? "Nil")")
      self.userData.appleId = self.apple.id
      print("self.userData.appleId: \(self.userData.appleId?.uuidString ?? "Nil")")
    }) {
      Text("Use Apple")
    }
    Text("self.apple.id: \(self.apple.id.uuidString)")
    Text("self.userData.appleId: \(self.userData.appleId?.uuidString ?? "Nil")")
  }
  ... // Code Omitted For Brevity
}

ButtonAppleDetail中的打印语句的输出为:

  

self.userData.appleId:无   self.userData.appleId:28EE7739-5E5A-4CA4-AFF5-7A6BFE025250

Text中显示self.userData.appleId的{​​{1}}视图始终为ContentView。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:0)

在Beta 5中,ObservableObject不再使用willChange。它改为使用objectWillChange。此外,它还可以自动合成主题,因此您不必自己编写主题(尽管您可以根据需要覆盖它)。

最重要的是,有一个新的属性包装器(@Published),它将对属性进行更改以使发布者发出。无需手动调用.send(),因为它将自动完成。因此,如果在您的代码中像这样重写UserData类,它将正常工作:

final class UserData: ObservableObject {
    @Published var apples = appleData
    @Published var appleId = appleUUID
}