Pada artikel ini, kita akan melihat enam operator Gabungkan yang berguna. Kami akan melakukan ini dengan contoh, bereksperimen dengan masing-masing di Xcode Playground.
Kode sumber tersedia di akhir artikel.
Nah, tanpa basa-basi lagi, mari kita mulai.
1. tambahkan
Kelompok pernyataan ini memungkinkan kami untuk menambahkan (secara harfiah "menambahkan") acara, nilai, atau penerbit lain ke penerbit asli kami:
import Foundation
import Combine
var subscriptions = Set<AnyCancellable>()
func prependOutputExample() {
let stringPublisher = ["World!"].publisher
stringPublisher
.prepend("Hello")
.sink(receiveValue: { print($0) })
.store(in: &subscriptions)
}
Hasil:
Hellodan World! adalah keluaran dalam urutan berurutan:
Sekarang mari tambahkan penerbit lain dengan tipe yang sama:
func prependPublisherExample() {
let subject = PassthroughSubject<String, Never>()
let stringPublisher = ["Break things!"].publisher
stringPublisher
.prepend(subject)
.sink(receiveValue: { print($0) })
.store(in: &subscriptions)
subject.send("Run code")
subject.send(completion: .finished)
}
Hasilnya mirip dengan yang sebelumnya (perhatikan bahwa kita perlu mengirim acara
.finishedke subjek agar operator .prependberfungsi):
2. menambahkan
Operator
.append(secara harfiah "tambahkan ke akhir") bekerja dengan cara yang sama .prepend, tetapi dalam kasus ini kami menambahkan nilai ke penerbit asli:
func appendOutputExample() {
let stringPublisher = ["Hello"].publisher
stringPublisher
.append("World!")
.sink(receiveValue: { print($0) })
.store(in: &subscriptions)
}
Hasilnya, kami melihat
Hellodan World! dikeluarkan ke konsol:
Mirip dengan apa yang kita gunakan sebelumnya
.prependuntuk menambahkan Publishera, kita juga memiliki opsi ini untuk operator .append:
3. beralih ke terbaru
Operator yang lebih kompleks
.switchToLatestmemungkinkan kami menggabungkan serangkaian penayang menjadi satu aliran peristiwa:
func switchToLatestExample() {
let stringSubject1 = PassthroughSubject<String, Never>()
let stringSubject2 = PassthroughSubject<String, Never>()
let stringSubject3 = PassthroughSubject<String, Never>()
let subjects = PassthroughSubject<PassthroughSubject<String, Never>, Never>()
subjects
.switchToLatest()
.sink(receiveValue: { print($0) })
.store(in: &subscriptions)
subjects.send(stringSubject1)
stringSubject1.send("A")
subjects.send(stringSubject2)
stringSubject1.send("B") //
stringSubject2.send("C")
stringSubject2.send("D")
subjects.send(stringSubject3)
stringSubject2.send("E") //
stringSubject2.send("F") //
stringSubject3.send("G")
stringSubject3.send(completion: .finished)
}
Inilah yang terjadi di kode:
- Kami membuat tiga objek
PassthroughSubjectyang akan kami kirim nilai. - Kami membuat objek utama
PassthroughSubjectyang mengirimkan objek lainPassthroughSubject. - Kami mengirim
stringSubject1ke subjek utama. stringSubject1mendapat nilai A.- Kami mengirimkan
stringSubject2ke subjek utama, secara otomatis membuang peristiwa stringSubject1. - Demikian pula, kami mengirim nilai ke
stringSubject2, terhubung ke,stringSubject3dan mengirimkan acara penyelesaian ke sana.
Hasilnya adalah output
A, C, Ddan G:
Untuk mempermudah, fungsi
isAvailablemengembalikan nilai acak Boolsetelah beberapa penundaan.
func switchToLatestExample2() {
func isAvailable(query: String) -> Future<Bool, Never> {
return Future { promise in
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
promise(.success(Bool.random()))
}
}
}
let searchSubject = PassthroughSubject<String, Never>()
searchSubject
.print("subject")
.map { isAvailable(query: $0) }
.print("search")
.switchToLatest()
.sink(receiveValue: { print($0) })
.store(in: &subscriptions)
searchSubject.send("Query 1")
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
searchSubject.send( "Query 2")
}
}
Terima kasih kepada operator,
.switchToLatestkami mencapai apa yang kami inginkan. Hanya satu nilai Bool yang akan ditampilkan:
4. bergabung (dengan :)
Kami menggunakan
.merge(with:)untuk menggabungkan dua Publishersseolah-olah kami mendapatkan nilai hanya dari satu:
func mergeWithExample() {
let stringSubject1 = PassthroughSubject<String, Never>()
let stringSubject2 = PassthroughSubject<String, Never>()
stringSubject1
.merge(with: stringSubject2)
.sink(receiveValue: { print($0) })
.store(in: &subscriptions)
stringSubject1.send("A")
stringSubject2.send("B")
stringSubject2.send("C")
stringSubject1.send("D")
}
Hasilnya adalah urutan elemen yang bergantian:
5.combineLatest
Operator
.combineLatestmenerbitkan tupel yang berisi nilai terbaru dari setiap penerbit.
Untuk menggambarkan hal ini, pertimbangkan contoh dunia nyata berikut: kami memiliki nama pengguna, kata sandi,
UITextFieldsdan tombol lanjutkan. Kami ingin tetap menonaktifkan tombol hingga nama pengguna setidaknya terdiri dari lima karakter dan kata sandi setidaknya delapan karakter. Kami dapat dengan mudah mencapai ini menggunakan operator .combineLatest:
func combineLatestExample() {
let usernameTextField = CurrentValueSubject<String, Never>("")
let passwordTextField = CurrentValueSubject<String, Never>("")
let isButtonEnabled = CurrentValueSubject<Bool, Never>(false)
usernameTextField
.combineLatest(passwordTextField)
.handleEvents(receiveOutput: { (username, password) in
print("Username: \(username), password: \(password)")
let isSatisfied = username.count >= 5 && password.count >= 8
isButtonEnabled.send(isSatisfied)
})
.sink(receiveValue: { _ in })
.store(in: &subscriptions)
isButtonEnabled
.sink { print("isButtonEnabled: \($0)") }
.store(in: &subscriptions)
usernameTextField.send("user")
usernameTextField.send("user12")
passwordTextField.send("12")
passwordTextField.send("12345678")
}
Sekali
usernameTextField dan passwordTextFieldterima user12, dan dengan 12345678demikian, kondisinya terpenuhi, dan tombol diaktifkan:
6. zip
Operator
.zipmengirimkan sepasang nilai yang cocok dari setiap penerbit. Katakanlah kita ingin menentukan apakah kedua penerbit telah menerbitkan nilai yang sama Int:
func zipExample() {
let intSubject1 = PassthroughSubject<Int, Never>()
let intSubject2 = PassthroughSubject<Int, Never>()
let foundIdenticalPairSubject = PassthroughSubject<Bool, Never>()
intSubject1
.zip(intSubject2)
.handleEvents(receiveOutput: { (value1, value2) in
print("value1: \(value1), value2: \(value2)")
let isIdentical = value1 == value2
foundIdenticalPairSubject.send(isIdentical)
})
.sink(receiveValue: { _ in })
.store(in: &subscriptions)
foundIdenticalPairSubject
.sink(receiveValue: { print("is identical: \($0)") })
.store(in: &subscriptions)
intSubject1.send(0)
intSubject1.send(1)
intSubject2.send(4)
intSubject1.send(6)
intSubject2.send(1)
intSubject2.send(7)
intSubject2.send(9) // ,
}
Kami memiliki nilai yang sesuai berikut dari
intSubject1dan intSubject2:
- 0 dan 4
- 1 dan 1
- 6 dan 7
Nilai terakhir
9tidak ditampilkan karena nilai intSubject1terkait belum dipublikasikan:
Sumber daya
Kode sumber tersedia di Gist .
Kesimpulan
Tertarik dengan jenis operator Combine lainnya? Silakan kunjungi artikel saya yang lain: