Swift 合并,避免嵌套订阅者可选
Swift Combine, Avoid nested subscribers on optionals
我有一个包含用户对象的 AccountService class。用户对象从网络请求中设置为异步。
在我的 UI 中,我正在显示用户并希望使更改保持最新。我正在使用 Swift Combine Framework 来执行此操作。
问题:有没有办法避免对象上的嵌套订阅者?
我写了一些测试代码来说明这一点:
import UIKit
import Combine
class User: ObservableObject, CustomDebugStringConvertible {
@Published
var name: String
init(name: String) {
self.name = name
}
var debugDescription: String {
return self.name
}
}
class AccountService {
@Published
var user: User? = nil
var userCancel: AnyCancellable?
var userContentCancel: AnyCancellable?
init() {
self.userCancel = self.$user.sink { (user) in
print("Set user: \(String(describing: user))")
guard let user = user else { return }
self.userContentCancel = user.$name.sink { _ in
print("new name: \(String(describing: self.user))")
}
}
}
func setUseru(user: User) {
self.user = user
}
func changeUserName(name: String) {
self.user?.name = name
}
}
let x = AccountService()
x.setUseru(user: User(name: "Philipp"))
x.changeUserName(name: "Tom")
x.setUseru(user: User(name: "Anna"))
运行 在 Playgroud Xcode 版本 11.4.1,Swift 5
输出
Set user: nil
Set user: Optional(Philipp)
new name: nil
new name: Optional(Philipp)
Set user: Optional(Anna)
new name: Optional(Tom)
理想情况下,我只想听 self.$user.sink
对象设置的时间 AND 对象内容更改的时间。
我在设置用户名时尝试过 self.objectWillChange.send()
,但我无法触发外部发布者。
我正在寻找摆脱的方法
guard let user = user else { return }
self.userContentCancel = user.$name.sink { _ in
print("new name: \(String(describing: self.user))")
}
在我的实现中,只是从相同的 self.$user.sink { (user) in
实现中驱动所有内容。
是的,有办法。您可以简单地使用 Combine 的 flatMap 运算符:
Transforms all elements from an upstream publisher into a new publisher up to a maximum number of publishers you specify.
我的工作示例:
import Foundation
import Combine
class User: ObservableObject {
@Published var name: String
init(name: String) {
self.name = name
}
var debugDescription: String {
return self.name
}
}
class AccountService {
@Published var user: User? = nil
var userCancel: AnyCancellable?
init() {
self.userCancel = self.$user
.filter { [=10=] != nil }
.flatMap { [=10=]!.$name }
.sink(receiveValue: { name in
print(name)
})
}
func setUseru(user: User) {
self.user = user
}
func changeUserName(name: String) {
self.user?.name = name
}
}
let x = AccountService()
x.setUseru(user: User(name: "Philipp"))
x.changeUserName(name: "Tom")
x.setUseru(user: User(name: "Anna"))
程序的输出将是:
Philipp
Tom
Anna
我有一个包含用户对象的 AccountService class。用户对象从网络请求中设置为异步。 在我的 UI 中,我正在显示用户并希望使更改保持最新。我正在使用 Swift Combine Framework 来执行此操作。
问题:有没有办法避免对象上的嵌套订阅者?
我写了一些测试代码来说明这一点:
import UIKit
import Combine
class User: ObservableObject, CustomDebugStringConvertible {
@Published
var name: String
init(name: String) {
self.name = name
}
var debugDescription: String {
return self.name
}
}
class AccountService {
@Published
var user: User? = nil
var userCancel: AnyCancellable?
var userContentCancel: AnyCancellable?
init() {
self.userCancel = self.$user.sink { (user) in
print("Set user: \(String(describing: user))")
guard let user = user else { return }
self.userContentCancel = user.$name.sink { _ in
print("new name: \(String(describing: self.user))")
}
}
}
func setUseru(user: User) {
self.user = user
}
func changeUserName(name: String) {
self.user?.name = name
}
}
let x = AccountService()
x.setUseru(user: User(name: "Philipp"))
x.changeUserName(name: "Tom")
x.setUseru(user: User(name: "Anna"))
运行 在 Playgroud Xcode 版本 11.4.1,Swift 5
输出
Set user: nil
Set user: Optional(Philipp)
new name: nil
new name: Optional(Philipp)
Set user: Optional(Anna)
new name: Optional(Tom)
理想情况下,我只想听 self.$user.sink
对象设置的时间 AND 对象内容更改的时间。
我在设置用户名时尝试过 self.objectWillChange.send()
,但我无法触发外部发布者。
我正在寻找摆脱的方法
guard let user = user else { return }
self.userContentCancel = user.$name.sink { _ in
print("new name: \(String(describing: self.user))")
}
在我的实现中,只是从相同的 self.$user.sink { (user) in
实现中驱动所有内容。
是的,有办法。您可以简单地使用 Combine 的 flatMap 运算符:
Transforms all elements from an upstream publisher into a new publisher up to a maximum number of publishers you specify.
我的工作示例:
import Foundation
import Combine
class User: ObservableObject {
@Published var name: String
init(name: String) {
self.name = name
}
var debugDescription: String {
return self.name
}
}
class AccountService {
@Published var user: User? = nil
var userCancel: AnyCancellable?
init() {
self.userCancel = self.$user
.filter { [=10=] != nil }
.flatMap { [=10=]!.$name }
.sink(receiveValue: { name in
print(name)
})
}
func setUseru(user: User) {
self.user = user
}
func changeUserName(name: String) {
self.user?.name = name
}
}
let x = AccountService()
x.setUseru(user: User(name: "Philipp"))
x.changeUserName(name: "Tom")
x.setUseru(user: User(name: "Anna"))
程序的输出将是:
Philipp
Tom
Anna