13

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

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这种方式将该数组绑定到视图,实际上每次刷新时都会添加一个新点?

4

3 回答 3

13

为确保您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)
    }
}
于 2019-08-13T13:48:49.247 回答
1

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

于 2019-11-12T21:30:40.517 回答
0

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

  1. 创建了一个 Observable 对象并使用 @Published 包装器包装所需的属性
  2. 使用您将在步骤 3 中创建的方法通过可表示视图中的 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)
      }
    }
于 2021-11-27T12:34:04.513 回答