如何使用 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的主要内容,如果未能解决你的问题,请参考以下文章
如何告诉 SwiftUI 视图绑定到多个嵌套的 ObservableObject
调用 ObservableObject 类初始化器来更新 SwiftUI 中的 List