W trybie imperatywnym Szybki często stosuje się właściwości obliczeniowe, aby zapewnić wygodny dostęp do danych bez powielania stanu.
Powiedzmy, że mam tę klasę do bezwzględnego użycia 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
}
// ...
}
Jeśli chcę utworzyć reaktywny ekwiwalent za pomocą Łączenia, np. Do użytku ze SwiftUI, mogę łatwo dodać @Published
do przechowywanych właściwości w celu wygenerowania Publisher
s, ale nie dla właściwości obliczonych.
@Published var userIsLoggedIn: Bool { // Error: Property wrapper cannot be applied to a computed property
currentUser != nil
}
Istnieją różne obejścia, o których mógłbym pomyśleć. Mógłbym zamiast tego zapisać moją właściwość obliczoną i aktualizować ją.
Opcja 1: Korzystanie z obserwatora właściwości:
class ReactiveUserManager1: ObservableObject {
@Published private(set) var currentUser: User? {
didSet {
userIsLoggedIn = currentUser != nil
}
}
@Published private(set) var userIsLoggedIn: Bool = false
// ...
}
Opcja 2: Korzystanie z Subscriber
własnej klasy:
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)
}
// ...
}
Jednak te obejścia nie są tak eleganckie, jak obliczone właściwości. Powielają stan i nie aktualizują obu właściwości jednocześnie.
Jaki byłby odpowiedni odpowiednik dodania Publisher
do obliczonej właściwości w Combine?
ObservableObject
. Zakładasz z natury, żeObservableObject
obiekt powinien mieć zdolność mutowania, co z definicji nie ma miejsca w przypadku właściwości obliczonej .Odpowiedzi:
Co powiesz na użycie downstream?
W ten sposób subskrypcja otrzyma element z góry, a następnie możesz użyć
sink
lubassign
zrobićdidSet
pomysł.źródło
Utwórz nowego wydawcę subskrybującego usługę, którą chcesz śledzić.
Będziesz wtedy mógł obserwować go podobnie jak swoją
@Published
własność.Nie są bezpośrednio powiązane, ale są przydatne, można w ten sposób śledzić wiele właściwości
combineLatest
.źródło
Powinieneś zadeklarować PassthroughSubject w swoim ObservableObject:
A w didSet (willSet może być lepiej) w twoim @Published var będziesz używał metody o nazwie send ()
Możesz to sprawdzić w rozmowie o przepływie danych WWDC
źródło
@Published
opakowanie iPassthroughSubject
oba służą w tym samym celu. Zwróć uwagę na to, co napisałeś i co tak naprawdę chciał osiągnąć PO. Czy twoje rozwiązanie stanowi lepszą alternatywę niż opcja 1 ?scan ( : :) Przekształca elementy z wcześniejszego wydawcy, dostarczając bieżący element do zamknięcia wraz z ostatnią wartością zwróconą przez zamknięcie.
Możesz użyć scan (), aby uzyskać najnowszą i aktualną wartość. Przykład:
Powyższy kod jest równoważny z tym: (mniej Połącz)
źródło