如何使用 ObservableObject 更新 UIViewRepresentable

Posted

技术标签:

【中文标题】如何使用 ObservableObject 更新 UIViewRepresentable【英文标题】:How to update UIViewRepresentable with ObservableObject 【发布时间】:2019-12-20 00:48:11 【问题描述】:

我正在尝试学习与 SwiftUI 结合,我正在努力如何使用 ObservableObject(以前的 BindableObject)更新我的视图(来自 UIKit)。问题是,很明显,一旦@Published 对象发送它已更改的通知,方法updateUIView 将不会触发。

class DataSource: ObservableObject 
    @Published var locationCoordinates = [CLLocationCoordinate2D]()
    var value: Int = 0

    init() 
        Timer.scheduledTimer(withTimeInterval: 3, repeats: true)  timer in
            self.value += 1
            self.locationCoordinates.append(CLLocationCoordinate2D(latitude: 52, longitude: 16+0.1*Double(self.value)))
        
    


struct MyView: UIViewRepresentable 
    @ObservedObject var dataSource = DataSource()

    func makeUIView(context: Context) -> MKMapView 
        MKMapView(frame: .zero)
    

    func updateUIView(_ view: MKMapView, context: Context) 
        let newestCoordinate = dataSource.locationCoordinates.last ?? CLLocationCoordinate2D(latitude: 52, longitude: 16)
        let annotation = MKPointAnnotation()
        annotation.coordinate = newestCoordinate
        annotation.title = "Test #\(dataSource.value)"
        view.addAnnotation(annotation)
    

如何将locationCoordinates 数组绑定到视图,这样每次刷新时实际上都会添加一个新点?

【问题讨论】:

你有没有找到不拔掉它的方法? 【参考方案1】:

我将为使用 combine 表示的任何 UI/NS 视图提供通用解决方案。我的方法有性能优势。

    创建了一个 Observable 对象并用 @Published 包装器 在视图中通过updateView方法注入Observed对象 可使用您将在第 3 步中创建的方法表示 使用视图模型作为参数对所需视图进行子类化。 创建一个 addViewModel 方法并使用 合并运营商/订阅者并将其添加到可取消。

注意 - 非常适用于环境对象。

    struct swiftUIView : View 
      @EnvironmentObject var env : yourViewModel
      ...
      ...
          UIViewRep(wm : env)
     

    struct UIViewRep : UIViewRepresentable 

     var wm : yourViewModel
     
     func makeUIView 
      let yv = yourView()
      yv.addViewModel(wm)
      return yv
      

    class yourView : UIView 
     var viewModel : yourViewModel?
     var cancellable = Set<AnyCancellable>()
     ...
     ...
     func addViewModel( _ wm : yourViewModel) 
     self.viewModel = wm

      self.viewModel?.desiredProperty
          .sink(receiveValue:  [unowned self] w in
        print("Make changes with ", w)
       ).store(in: &cancellable)
      
    

【讨论】:

【参考方案2】:

这个解决方案对我有用,但使用 EnvironmentObject https://gist.github.com/svanimpe/152e6539cd371a9ae0cfee42b374d7c4

【讨论】:

【参考方案3】:

为确保您的ObservedObject 不会被多次创建(您只需要一份),您可以将其放在您的UIViewRepresentable 之外:

import SwiftUI
import MapKit

struct ContentView: View 
    @ObservedObject var dataSource = DataSource()

    var body: some View 
        MyView(locationCoordinates: dataSource.locationCoordinates, value: dataSource.value)
    

class DataSource: ObservableObject 
    @Published var locationCoordinates = [CLLocationCoordinate2D]()
    var value: Int = 0

    init() 
        Timer.scheduledTimer(withTimeInterval: 3, repeats: true)  timer in
            self.value += 1
            self.locationCoordinates.append(CLLocationCoordinate2D(latitude: 52, longitude: 16+0.1*Double(self.value)))
        
    


struct MyView: UIViewRepresentable 
    var locationCoordinates: [CLLocationCoordinate2D]
    var value: Int

    func makeUIView(context: Context) -> MKMapView 
        MKMapView(frame: .zero)
    

    func updateUIView(_ view: MKMapView, context: Context) 
        print("I am being called!")
        let newestCoordinate = locationCoordinates.last ?? CLLocationCoordinate2D(latitude: 52, longitude: 16)
        let annotation = MKPointAnnotation()
        annotation.coordinate = newestCoordinate
        annotation.title = "Test #\(value)"
        view.addAnnotation(annotation)
    

【讨论】:

我宁愿通过另一个东西(一个交互器)注入模型,它不是从 View 类继承的。有没有其他方法可以在不创建从 View 继承的结构的情况下观察它?你所做的基本上是把它包裹起来,虽然它确实有效,但它并没有显示修复 UIViewRepresentable 问题本身。另外,我认为您的解决方案无法修复多次创建 ObservedObject。 UIViewRepresentable 在这里和那里只创建一次,因此不会多次创建。如果您的意思是一旦重新创建视图就会重新创建它 - 那么这两种情况都会发生。 是的 - 我有同样的问题,唯一的解决方法是将我的数据源保存在环境中 - 否则它会被重新创建,无论我把它放在哪里。

以上是关于如何使用 ObservableObject 更新 UIViewRepresentable的主要内容,如果未能解决你的问题,请参考以下文章

如何链接 ObservableObject?

如何告诉 SwiftUI 视图绑定到多个嵌套的 ObservableObject

调用 ObservableObject 类初始化器来更新 SwiftUI 中的 List

ObservableObject 不更新视图

在子视图中更新 ObservableObject 的 @Published 变量

如果数组是 ObservableObject 的成员,如何绑定数组和 List?