【问题标题】:SwiftUI - ObservableObject Update from CoordinatorSwiftUI - 来自 Coordinator 的 ObservableObject 更新
【发布时间】:2019-11-29 16:19:28
【问题描述】:

UIViewControllerRepresentable 从 ViewController 接收图像。此图像应可用于 SwiftUI 视图。

ObservableObject:

class CurrentImage: ObservableObject  {
 var didChange = PassthroughSubject<Void, Never>()
 @Published var photoTaken: UIImage? = nil {didSet{didChange.send()}}
}

UIViewControllerRepresentable:

struct CameraPreviewView: UIViewControllerRepresentable  {

 var currentImage: CurrentImage

 func makeCoordinator() -> Coordinator {
  Coordinator(self)
 }

 class Coordinator: NSObject {
  let parent: CameraPreviewView

  init(_ cameraPreviewController: CameraPreviewView) {
   self.parent = cameraPreviewController
   super.init()

   // Notification receives a copy of the image taken from the ViewController:         
   NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "imageDidChange"), object: nil, queue: OperationQueue.main){(notification) in
    if let image = notification.userInfo?["image"] as? UIImage {

      // *****ERROR: self.parent.videoStatus.photoTaken is not accessible
      self.parent.currentImage.photoTaken = image
    }
   }
  }
 }


    func makeUIViewController(context: UIViewControllerRepresentableContext<CameraPreviewView>) -> CameraViewController {
        let cameraViewController = CameraViewController()
        return cameraViewController
    }

    // View is not updating so we don't need this
    func updateUIViewController(_ cameraViewController: CameraViewController, context: UIViewControllerRepresentableContext<CameraPreviewView>) {
    }
}

ObservableObject 是“不可访问的”,因此我无法从协调器中设置图像。我在这里忽略了一些简单的事情吗?

更新 2:将值传递给 ObservableObject 仍然无法正常工作

我一直在努力解决这个问题,并尝试了十几种方法组合。但为了简化问题,我们有一个 Coordinator,其 var 代表一个 ObservableObject。在这种情况下,我将保持简单并尝试设置字符串的值。

协调员:

struct CameraPreviewView: UIViewControllerRepresentable  {

 var cameraPhoto = CurrentPhoto()

 func makeCoordinator() -> Coordinator {
  Coordinator(self)
 }

 class Coordinator: NSObject {
  let parent: CameraPreviewView
  init(_ cameraPreviewController: CameraPreviewView) {
   self.parent = cameraPreviewController
   super.init()

   NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "imageDidChange"), object: nil, queue: OperationQueue.main){(notification) in
    print("notice received")
    self.parent.cameraPhoto.testString = "This changed"
   }
  }
 }
}...

ObservableObject:

 class CurrentPhoto: ObservableObject  {
  @Published var testString = "Testing string"
 }

为了测试这一点,我还尝试了以下方法:

class CurrentPhoto: ObservableObject  {

 let objectWillChange = ObservableObjectPublisher()

 var testString = "Testing String" {
  willSet {
   print("set string")
   objectWillChange.send()
  }
 }
}

在第二个示例中,将调用 willSet 方法。 (它打印“设置字符串”)但是值仍然是“测试字符串”。

正在从控制器调用 ObservableObject,但值未设置或更改。

因此视图没有收到新值:

struct ContentView: View {
 @ObservedObject var cameraState = CurrentPhoto()
 var body: some View {
  VStack{
   Text("test this \(cameraState.testString)")
   ...   

注意:将值从 VIEW 传递给 ObservableObject 是可行的,因此问题与协调器如何将值传递给 ObservedObject 的方式有关。

以下工作并将值从 View 传递给 OO:

Button(action : {
 self.cameraState.testString = "from view"
}, label : {
 Text("Change string")
}

【问题讨论】:

  • videoStatus 未在您的 sn-p 中声明。这是什么?
  • 是的,抱歉,videoStatus 已更改为 currentImage。它旨在反映 ObservableObject。我确实想出了一个解决方案,我很快就会发布。

标签: swift swiftui


【解决方案1】:

这并不能完全解决如何将 Coordinator 绑定到 ObservableObject 的问题。不过,这确实达到了预期的目标,即将 Coordinator 中的图像返回给 SwiftUI。

观点:

struct ContentView: View {

 @State private var photoInView: Image?
 @State var isRecording = true

 var body: some View {
  VStack{
   photoInView?
   .resizable()
   .scaledToFit() 
   ZStack (alignment: .bottom) {
   // Start up the CameraPreview and this will 2-way bind.  
   CameraPreviewView(isRecording: $isRecording, photoReceivedFromCoordinator: $photoInView)
   ....

然后在 UIViewRepresentable 中:

struct CameraPreviewView: UIViewControllerRepresentable  {

  @Binding var isRecording: Bool
  @Binding var photoReceivedFromCoordinator: Image?

  func makeCoordinator() -> Coordinator {
   Coordinator(self)
  }

  class Coordinator: NSObject {
   // Setting the coordinator to parent allows the coordinator to use the    @Binding
   let parent: CameraPreviewView
   init(_ cameraPreviewController: CameraPreviewView) {
    self.parent = cameraPreviewController
    super.init()

    NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "imageDidChange"), object: nil, queue: OperationQueue.main){(notification) in
    if let uiImage = notification.userInfo?["image"] as? UIImage {
     // We need an Image not a UI Image, so first we convert it
     let image = Image(uiImage: uiImage)
     // Assign the value to the parent's binding value
     self.parent.photoReceivedFromCoordinator = image
    }
   }
  }
 }

【讨论】:

    猜你喜欢
    • 2021-02-27
    • 1970-01-01
    • 2021-12-11
    • 2021-10-14
    • 1970-01-01
    • 2020-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多