在命令式Swift中,通常使用计算(computed)属性来方便地访问数据,而不复制状态.
假设我有一个为强制MVC使用而设计的类:
class ImperativeUserManager {
private(set) var currentUser: User? {
didSet {
if oldValue != currentUser {
NotificationCenter.default.post(name: NSNotification.Name("userStateDidChange"), object: nil)
// Observers that receive this notification might then check either currentUser or userIsLoggedIn for the latest state
}
}
}
var userIsLoggedIn: Bool {
currentUser != nil
}
// ...
}
如果我想用Combine创建一个react 性类似功能,例如与SwiftUI一起使用,我可以很容易地将@Published
添加到存储属性中以生成Publisher
s,但不能用于计算(computed)属性.
@Published var userIsLoggedIn: Bool { // Error: Property wrapper cannot be applied to a computed property
currentUser != nil
}
我可以想出各种各样的解决办法.我可以将我的计算(computed)属性存储起来并保持更新.
选项1:使用属性观察者:
class ReactiveUserManager1: ObservableObject {
@Published private(set) var currentUser: User? {
didSet {
userIsLoggedIn = currentUser != nil
}
}
@Published private(set) var userIsLoggedIn: Bool = false
// ...
}
选项2:在我自己的课堂上使用Subscriber
分:
class ReactiveUserManager2: ObservableObject {
@Published private(set) var currentUser: User?
@Published private(set) var userIsLoggedIn: Bool = false
private var subscribers = Set<AnyCancellable>()
init() {
$currentUser
.map { $0 != nil }
.assign(to: \.userIsLoggedIn, on: self)
.store(in: &subscribers)
}
// ...
}
然而,这些变通方法并不像计算(computed)属性那样优雅.它们复制状态,并且不会同时更新两个属性.
在Combine中,将Publisher
添加到计算(computed)属性的正确类似功能是什么?