Im zwingenden Swift ist es üblich, berechnete Eigenschaften zu verwenden, um einen bequemen Zugriff auf Daten zu ermöglichen, ohne den Status zu duplizieren.
Angenommen, ich habe diese Klasse für die zwingende Verwendung von MVC erstellt:
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
}
// ...
}
Wenn ich mit Combine ein reaktives Äquivalent erstellen möchte, z. B. zur Verwendung mit SwiftUI, kann ich @Published
gespeicherte Eigenschaften problemlos hinzufügen , um Publisher
s zu generieren , jedoch nicht für berechnete Eigenschaften.
@Published var userIsLoggedIn: Bool { // Error: Property wrapper cannot be applied to a computed property
currentUser != nil
}
Es gibt verschiedene Problemumgehungen, an die ich denken könnte. Ich könnte stattdessen meine berechnete Eigenschaft speichern und auf dem neuesten Stand halten.
Option 1: Verwenden eines Eigenschaftsbeobachters:
class ReactiveUserManager1: ObservableObject {
@Published private(set) var currentUser: User? {
didSet {
userIsLoggedIn = currentUser != nil
}
}
@Published private(set) var userIsLoggedIn: Bool = false
// ...
}
Option 2: Verwenden von a Subscriber
in meiner eigenen Klasse:
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)
}
// ...
}
Diese Problemumgehungen sind jedoch nicht so elegant wie berechnete Eigenschaften. Sie duplizieren den Status und aktualisieren nicht beide Eigenschaften gleichzeitig.
Was wäre ein angemessenes Äquivalent zum Hinzufügen von a Publisher
zu einer berechneten Eigenschaft in Combine?
ObservableObject
. Sie gehen von Natur aus davon aus, dass einObservableObject
Objekt mutieren kann, was per Definition für die berechnete Eigenschaft nicht der Fall ist .Antworten:
Wie wäre es mit Downstream?
Auf diese Weise erhält das Abonnement ein Element aus dem Upstream, dann können Sie die Idee verwenden
sink
oder ausführen.assign
didSet
quelle
Erstellen Sie einen neuen Herausgeber, der die Eigenschaft abonniert hat, die Sie verfolgen möchten.
Sie können es dann ähnlich wie Ihr
@Published
Eigentum beobachten.Nicht direkt verwandt, aber dennoch nützlich, können Sie auf diese Weise mehrere Eigenschaften verfolgen
combineLatest
.quelle
Sie sollten ein PassthroughSubject in Ihrem ObservableObject deklarieren :
Und im didSet (willSet könnte besser sein) Ihrer @Published var verwenden Sie eine Methode namens send ()
Sie können dies im WWDC Data Flow Talk überprüfen
quelle
@Published
Wrapper undPassthroughSubject
beide dienen in diesem Zusammenhang demselben Zweck. Achten Sie darauf, was Sie geschrieben haben und was das OP eigentlich erreichen wollte. Dient Ihre Lösung als bessere Alternative als die Option 1 ?scan ( : :) Transformiert Elemente aus dem Upstream-Publisher, indem das aktuelle Element zusammen mit dem letzten vom Abschluss zurückgegebenen Wert für einen Abschluss bereitgestellt wird.
Sie können scan () verwenden, um den neuesten und aktuellen Wert abzurufen. Beispiel:
Der obige Code entspricht dem: (weniger Kombinieren)
quelle