使用Combine设置发布服务器,同时满足非零变量初始值的要求



我对反应式编程概念相对陌生,我正在尝试构建一个简单的视图模型来更新@Published Bool值,这些值用于通过SwiftUI保持UI更新。

该特定模型在WatchConnectivity框架中的其他值随时间变化时基于这些值来设置Bool值。

尽管这是一个简单的例子,而且很有效,但我觉得我错过了减少裁员的机会。

具体地说,当我使用Publishers.CombineLatestPublishers.CombineLatest3时,我重复用于稍后设置appNotInstalledcomplicationNotInstalled的初始值的逻辑,这感觉很奇怪。

尽管初始值是通过发布者传递的,因此它们通过CombineLatest管道并设置初始值,但将发布的变量任意设置为truefalse感觉是错误的,但编译器让我在某个地方为它们设置初始值。

如果我不设置初始值,我会得到Variable 'self.appNotInstalled' used before being initialized错误。

有没有一种方法可以避免设置初始值,而不将其设为零,或者有没有另一种方法避免重复用于确定其值的逻辑?

这是我的工作代码:

class WatchConnectivityModel: ObservableObject {
// values used to show/hide UI
@Published var appNotInstalled: Bool
@Published var complicationNotInstalled: Bool
private var cancellables: [AnyCancellable] = []
init() {
// initialize based on the values of everything at class init
let activated = WCSession.default.activationState == .activated
let appInstalled = WCSession.default.isWatchAppInstalled
let complicationInstalled = WCSession.default.isComplicationEnabled
appNotInstalled = !(activated && appInstalled)
complicationNotInstalled = activated && appInstalled && !complicationInstalled
// set up the publishers for any changes
let activationStatePublisher = WCSession.default.publisher(for: .activationState)
let isWatchAppInstalledPublisher = WCSession.default
.publisher(for: .isWatchAppInstalled)
let isComplicationEnabledPublisher = WCSession.default
.publisher(for: .isComplicationEnabled)
// set up assignment of appNotInstalled for changes
Publishers.CombineLatest(activationStatePublisher.removeDuplicates(),
isWatchAppInstalledPublisher.removeDuplicates())
.map { (state, installed) in
// repeated logic from above
return !(state == .activated && installed)
}.receive(on: RunLoop.main)
.assign(to: .appNotInstalled, on: self)
.store(in: &cancellables)
// set up assignment of complicationNotInstalled for changes
Publishers.CombineLatest3(activationStatePublisher.removeDuplicates(),
isWatchAppInstalledPublisher.removeDuplicates(),
isComplicationEnabledPublisher.removeDuplicates())
.map { (state, appInstalled, complicationInstalled) in
// repeated logic again
return state == .activated && appInstalled && !complicationInstalled
}.receive(on: RunLoop.main)
.assign(to: .complicationNotInstalled, on: self)
.store(in: &cancellables)
}
}

我为每个创建了一个新的初始值设定项结构,它只包括每个的逻辑。每当我设置初始值或更新发布的变量时,我都会使用它来避免重复逻辑。如果有人对此有更好的解决方案,我愿意接受其他可能性。

import Foundation
import Combine
import WatchConnectivity
class WatchConnectivityModel: ObservableObject {
// values used to show/hide UI
@Published var appNotInstalled: Bool
@Published var complicationNotInstalled: Bool
private struct AppNotInstalled {
let value: Bool
init(_ activationState: WCSessionActivationState,
_ appInstalled: Bool) {
value = !(activationState == .activated && appInstalled)
}
}
private struct ComplicationNotInstalled {
let value: Bool
init(_ activationState: WCSessionActivationState,
_ appInstalled: Bool,
_ complicationInstalled: Bool) {
value = activationState == .activated && appInstalled && !complicationInstalled
}
}
private var cancellables: [AnyCancellable] = []
init() {
// initilize based on the current values
let state = WCSession.default.activationState
let appInstalled = WCSession.default.isWatchAppInstalled
let complicationInstalled = WCSession.default.isComplicationEnabled
appNotInstalled = AppNotInstalled(state,
appInstalled).value
complicationNotInstalled = ComplicationNotInstalled(state,
appInstalled,
complicationInstalled).value
// set up the publishers
let activationStatePublisher = WCSession.default
.publisher(for: .activationState)
let isWatchAppInstalledPublisher = WCSession.default
.publisher(for: .isWatchAppInstalled)
let isComplicationEnabledPublisher = WCSession.default
.publisher(for: .isComplicationEnabled)
// set up assignment of appNotInstalled
Publishers.CombineLatest(activationStatePublisher.removeDuplicates(),
isWatchAppInstalledPublisher.removeDuplicates())
.map { (state, installed) in
return AppNotInstalled(state, installed).value
}.receive(on: RunLoop.main)
.assign(to: .appNotInstalled,
on: self)
.store(in: &cancellables)
// set up assignment of complicationNotInstalled
Publishers.CombineLatest3(activationStatePublisher.removeDuplicates(),
isWatchAppInstalledPublisher.removeDuplicates(),
isComplicationEnabledPublisher.removeDuplicates())
.map { (state, appInstalled, complicationInstalled) in
return ComplicationNotInstalled(state, appInstalled, complicationInstalled).value
}.receive(on: RunLoop.main)
.assign(to: .complicationNotInstalled,
on: self)
.store(in: &cancellables)
}
}

最新更新