Dalam Swift imperatif, adalah umum untuk menggunakan properti yang dihitung untuk memberikan akses mudah ke data tanpa status duplikasi.
Katakanlah saya membuat kelas ini untuk penggunaan imperatif 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
}
// ...
}
Jika saya ingin membuat setara reaktif dengan Combine, misalnya untuk digunakan dengan SwiftUI, saya dapat dengan mudah menambahkan @Published
ke properti yang disimpan untuk menghasilkan Publisher
s, tetapi tidak untuk properti yang dihitung.
@Published var userIsLoggedIn: Bool { // Error: Property wrapper cannot be applied to a computed property
currentUser != nil
}
Ada berbagai solusi yang dapat saya pikirkan. Sebagai gantinya, saya dapat membuat properti yang dihitung disimpan dan tetap diperbarui.
Opsi 1: Menggunakan pengamat properti:
class ReactiveUserManager1: ObservableObject {
@Published private(set) var currentUser: User? {
didSet {
userIsLoggedIn = currentUser != nil
}
}
@Published private(set) var userIsLoggedIn: Bool = false
// ...
}
Opsi 2: Menggunakan a Subscriber
di kelas saya sendiri:
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)
}
// ...
}
Namun, solusi ini tidak seanggun properti yang dihitung. Mereka menduplikasi keadaan dan mereka tidak memperbarui kedua properti secara bersamaan.
Apa yang akan setara setara dengan menambahkan Publisher
ke properti yang dihitung di Combine?
ObservableObject
. Anda secara inheren berasumsi bahwa suatuObservableObject
objek harus dapat memiliki kemampuan bermutasi yang, menurut definisi, bukan kasus untuk Computed Property .Jawaban:
Bagaimana kalau menggunakan downstream?
Dengan cara ini, langganan akan mendapatkan elemen dari hulu, maka Anda bisa menggunakan
sink
atauassign
melakukandidSet
ide.sumber
Buat penerbit baru yang berlangganan properti yang ingin Anda lacak.
Anda kemudian dapat mengamatinya seperti
@Published
properti Anda .Meskipun tidak terkait langsung tetapi bermanfaat, Anda dapat melacak beberapa properti dengan cara itu
combineLatest
.sumber
Anda sholud mendeklarasikan PassthroughSubject di ObservableObject Anda:
Dan di didSet (willSet bisa lebih baik) dari var @Published Anda, Anda akan menggunakan metode yang disebut send ()
Anda dapat memeriksanya di WWDC Data Flow Talk
sumber
@Published
wrapper danPassthroughSubject
keduanya memiliki tujuan yang sama dalam konteks ini. Perhatikan apa yang Anda tulis dan apa yang ingin dicapai oleh OP. Apakah solusi Anda berfungsi sebagai alternatif yang lebih baik daripada opsi 1 sebenarnya?scan ( : :) Mengubah elemen dari penerbit hulu dengan memberikan elemen saat ini ke penutupan bersama dengan nilai terakhir yang dikembalikan oleh penutupan.
Anda dapat menggunakan pemindaian () untuk mendapatkan nilai terbaru dan saat ini. Contoh:
Kode di atas setara dengan ini: (kurang Kombinasikan)
sumber