No Swift imperativo, é comum usar propriedades computadas para fornecer acesso conveniente aos dados sem duplicar o estado.
Digamos que eu tenha essa classe feita para uso obrigatório do 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
}
// ...
}
Se eu quiser criar um equivalente reativo ao Combine, por exemplo, para uso com o SwiftUI, posso adicionar facilmente @Published
às propriedades armazenadas para gerar Publisher
s, mas não para propriedades calculadas.
@Published var userIsLoggedIn: Bool { // Error: Property wrapper cannot be applied to a computed property
currentUser != nil
}
Existem várias soluções alternativas em que pude pensar. Eu poderia tornar minha propriedade computada armazenada e mantê-la atualizada.
Opção 1: Usando um observador de propriedades:
class ReactiveUserManager1: ObservableObject {
@Published private(set) var currentUser: User? {
didSet {
userIsLoggedIn = currentUser != nil
}
}
@Published private(set) var userIsLoggedIn: Bool = false
// ...
}
Opção 2: usando a Subscriber
na minha própria classe:
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)
}
// ...
}
No entanto, essas soluções alternativas não são tão elegantes quanto as propriedades calculadas. Eles duplicam o estado e não atualizam as duas propriedades simultaneamente.
O que seria um equivalente adequado para adicionar a Publisher
a uma propriedade computada em Combine?
ObservableObject
. Você supõe inerentemente que umObservableObject
objeto possa ter capacidade de mutação que, por definição, não é o caso da Propriedade Computada .Respostas:
Que tal usar a jusante?
Dessa forma, a assinatura obterá um elemento do upstream, e você poderá usar
sink
ouassign
fazer adidSet
ideia.fonte
Crie um novo editor inscrito na propriedade que você deseja acompanhar.
Você poderá observá-lo como sua
@Published
propriedade.Não diretamente relacionado, mas útil, você pode acompanhar várias propriedades dessa maneira
combineLatest
.fonte
Você deve declarar um PassthroughSubject no seu ObservableObject:
E no didSet (willSet poderia ser melhor) do seu var @Published, você usará um método chamado send ()
Você pode verificá-lo no WWDC Data Flow Talk
fonte
@Published
wrapper ePassthroughSubject
ambos servem ao mesmo propósito neste contexto. Preste atenção no que você escreveu e no que o OP realmente queria alcançar. Sua solução serve como a melhor alternativa que a opção 1 realmente?scan ( : :) Transforma elementos do editor upstream, fornecendo o elemento atual a um fechamento junto com o último valor retornado pelo fechamento.
Você pode usar scan () para obter o valor mais recente e atual. Exemplo:
O código acima é equivalente a isso: (menos Combinar)
fonte