
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:
Hello
dan 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
.finished
ke subjek agar operator .prepend
berfungsi):

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
Hello
dan World
! dikeluarkan ke konsol:

Mirip dengan apa yang kita gunakan sebelumnya
.prepend
untuk menambahkan Publisher
a, kita juga memiliki opsi ini untuk operator .append
:

3. beralih ke terbaru
Operator yang lebih kompleks
.switchToLatest
memungkinkan 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
PassthroughSubject
yang akan kami kirim nilai. - Kami membuat objek utama
PassthroughSubject
yang mengirimkan objek lainPassthroughSubject
. - Kami mengirim
stringSubject1
ke subjek utama. stringSubject1
mendapat nilai A.- Kami mengirimkan
stringSubject2
ke subjek utama, secara otomatis membuang peristiwa stringSubject1. - Demikian pula, kami mengirim nilai ke
stringSubject2
, terhubung ke,stringSubject3
dan mengirimkan acara penyelesaian ke sana.
Hasilnya adalah output
A
, C
, D
dan G
:

Untuk mempermudah, fungsi
isAvailable
mengembalikan nilai acak Bool
setelah 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,
.switchToLatest
kami mencapai apa yang kami inginkan. Hanya satu nilai Bool yang akan ditampilkan:

4. bergabung (dengan :)
Kami menggunakan
.merge(with:)
untuk menggabungkan dua Publishers
seolah-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
.combineLatest
menerbitkan tupel yang berisi nilai terbaru dari setiap penerbit.
Untuk menggambarkan hal ini, pertimbangkan contoh dunia nyata berikut: kami memiliki nama pengguna, kata sandi,
UITextFields
dan 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 passwordTextField
terima user12
, dan dengan 12345678
demikian, kondisinya terpenuhi, dan tombol diaktifkan:

6. zip
Operator
.zip
mengirimkan 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
intSubject1
dan intSubject2
:
- 0 dan 4
- 1 dan 1
- 6 dan 7
Nilai terakhir
9
tidak ditampilkan karena nilai intSubject1
terkait belum dipublikasikan:

Sumber daya
Kode sumber tersedia di Gist .
Kesimpulan
Tertarik dengan jenis operator Combine lainnya? Silakan kunjungi artikel saya yang lain:
- 5 operator Gabungkan transformatif yang harus Anda ketahui
- 9 Gabungkan Operator Filter Yang Harus Anda Ketahui