如何通过另一个可观察对象观察已发布的属性 - Swift Combine
Posted
技术标签:
【中文标题】如何通过另一个可观察对象观察已发布的属性 - Swift Combine【英文标题】:How to observe a published property via another observable 0bject - Swift Combine 【发布时间】:2021-05-19 21:22:27 【问题描述】:[编辑]
我应该指出,我正在从大量传感器收集数据并且不得不污染视图模型,这就是编排这个,大量的 @Published 和订阅者代码变得非常乏味且容易出错。
我还编辑了代码以更能代表实际问题。
[原创] 在使用发布者时,我试图减少观察另一个类的结果所需的代码量。我宁愿从生成结果的类中发布结果,而不必将其传播回调用类。
这是一个显示问题的简单游乐场示例。
import SwiftUI
import Combine
class AnObservableObject: ObservableObject
@Published var flag: Bool = false
private var timerPub: Publishers.Autoconnect<Timer.TimerPublisher>
private var timerSub: AnyCancellable?
init()
timerPub = Timer.publish(every: 1, on: .current, in: .common)
.autoconnect()
func start()
timerSub = timerPub.sink [self] _ in
toggleFlag()
func stop()
timerSub?.cancel()
func toggleFlag()
flag.toggle()
class AnotherObservableObject: ObservableObject
let ao = AnObservableObject()
func start()
ao.start()
func stop()
ao.stop()
struct MyView: View
@StateObject var ao = AnotherObservableObject()
var body: some View
VStack
if ao.ao.flag
Image(systemName: "flag").foregroundColor(.green)
HStack
Button(action: ao.start(), label:
Text("Toggle Flag")
)
Button(action: ao.stop(), label:
Text("Stop")
)
.padding()
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
// Make a UIHostingController
let viewController = UIHostingController(rootView: MyView())
// Assign it to the playground's liveView
PlaygroundPage.current.liveView = viewController
let myView = MyView()
我让它工作的唯一方法就是这样做:
import SwiftUI
import Combine
class AnObservableObject: ObservableObject
let flag = CurrentValueSubject<Bool, Never>(false)
private var subscriptions = Set<AnyCancellable>()
private var timerPub: Publishers.Autoconnect<Timer.TimerPublisher>
private var timerSub: AnyCancellable?
init()
timerPub = Timer.publish(every: 1, on: .current, in: .common)
.autoconnect()
func start()
timerSub = timerPub.sink [self] _ in
toggleFlag()
func stop()
timerSub?.cancel()
func flagPublisher() -> AnyPublisher<Bool, Never>
return flag.eraseToAnyPublisher()
func toggleFlag()
flag.value.toggle()
class AnotherObservableObject: ObservableObject
let ao = AnObservableObject()
@Published var flag = false
init()
let flagPublisher = ao.flagPublisher()
flagPublisher
.receive(on: DispatchQueue.main)
.assign(to: &$flag)
func start()
ao.start()
func stop()
ao.stop()
struct MyView: View
@StateObject var ao = AnotherObservableObject()
var body: some View
VStack
if ao.flag
Image(systemName: "flag").foregroundColor(.green)
HStack
Button(action: ao.start(), label:
Text("Toggle Flag")
)
Button(action: ao.stop(), label:
Text("Stop")
)
.padding()
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
// Make a UIHostingController
let viewController = UIHostingController(rootView: MyView())
// Assign it to the playground's liveView
PlaygroundPage.current.liveView = viewController
let myView = MyView()
想法?
【问题讨论】:
当您需要在视图中直接使用ObservableObject
时,通常需要它。你这里为什么需要一个?如果你没有,你可以只使用结构而不是 AnObservableObject
希望几周后。你现在这样做的方式是链接它们的唯一方法
@loremipsum 谢谢,希望如此!如果 SwitftUI、Combine 和 pro Mac 获得重大更新,应该是一个退出事件!
【参考方案1】:
您不需要ObservableObject
;您可以直接在您的View
中观察Timer
。
struct MyView: View
@State private var flag: Bool = false
@State var timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
var body: some View
VStack
if flag
Image(systemName: "flag").foregroundColor(.green)
HStack
Button(action: start(), label:
Text("Toggle Flag")
)
Button(action: stop(), label:
Text("Stop")
)
.onReceive(timer) _ in
flag.toggle()
.padding()
func start()
timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
func stop()
timer.upstream.connect().cancel()
【讨论】:
感谢您的回答,我现在更新了我的代码,并提供了一个希望更好的解释。考虑收集位置数据,对其进行操作,然后将一些结果传递回视图,我想这样做而不必将这些结果传递回 viewModel。这只是我收集的数据点之一。以上是关于如何通过另一个可观察对象观察已发布的属性 - Swift Combine的主要内容,如果未能解决你的问题,请参考以下文章