[Combine 开发] combineLatest、merge、zip的使用区别

combineLatestmergezip 是三个常用的操作符,用于组合和处理流式数据。以下是它们的区别以及在 Combine 中的使用场景

combineLatest

combineLatest 操作符,用于将多个发布者的最新元素进行组合

当任何一个发布者发出新元素时,combineLatest 会将所有发布者的最新元素组合成一个元组,并将该元组发送给订阅者。

let publisher1 = PassthroughSubject<Int, Never>()
let publisher2 = PassthroughSubject<String, Never>()

let cancellable = publisher1
    .combineLatest(publisher2)
    .sink { (value1, value2) in
        print("Combined: (value1), (value2)")
    }

publisher1.send(1)
publisher2.send("A") // 输出 "Combined: 1, A"
publisher1.send(2)   // 输出 "Combined: 2, A"
publisher2.send("B") // 输出 "Combined: 2, B"

应用场景:

当你希望在多个输入源中的任意一个发生变化时,更新界面或执行某些操作时,combineLatest 是一个有用的操作符。

merge

merge 操作符,用于合并多个发布者的元素,无论它们来自哪个发布者,接收者都会按照它们的发出顺序进行接收

let publisher1 = PassthroughSubject<Int, Never>()
let publisher2 = PassthroughSubject<Int, Never>()

let cancellable = publisher1
    .merge(with: publisher2) 
    // .merge(with: pub2, pub3, 
    //        pub4, pub5, pub6,
    //        pub7, pub8) 
    //  最多可以merge8个  
    .sink { value in
        print("Merged: (value)")
    }

publisher1.send(1)   // 输出 "Merged: 1"
publisher2.send(2)   // 输出 "Merged: 2"
publisher1.send(3)   // 输出 "Merged: 3"
publisher2.send(4)   // 输出 "Merged: 4"

应用场景:

当你有多个来源的数据流,想要按照它们发生的顺序进行处理时,使用 merge 是一个常见的选择

zip

zip 操作符,用于将多个发布者的元素按顺序进行配对,形成元组

只有当所有发布者都发出了新元素时,zip 才会将这些元素组合成一个元组发送给订阅者

let publisher1 = PassthroughSubject<Int, Never>()
let publisher2 = PassthroughSubject<String, Never>()

_ = publisher1
    .zip(publisher2)
    .sink(receiveCompletion: { completion in
        print("结束了")
        switch completion {
        case .finished:
            print("完成")
        case .failure(let error):
            print("错误:(error.localizedDescription)")
        }
    }, receiveValue: { someValue in
        print("value: (someValue)")
    })

publisher1.send(1)
publisher1.send(2)
publisher1.send(3) 
publisher2.send("4")    // value: (1, "4")
publisher2.send("5")    // value: (2, "5")
   
//  有兴趣的朋友可以去试试send(completion: .finished)的情况
//  publisher1.send(completion: .finished)

当我想zip多个publisher可以试试下面的方法,最多可以zip4个publisher

let pub1 = PassthroughSubject<Int, Never>()
let pub2 = PassthroughSubject<String, Never>()
let pub3 = PassthroughSubject<String, Never>()
let pub4 = PassthroughSubject<String, Never>()
 
let cancellable = Publishers.Zip4(pub1, pub2, pub3, pub4)
    .sink { (value1, value2, value3, value4) in
        print("Zipped: (value1), (value2), (value3), (value4)")
    }

pub1.send(1)
pub1.send(2)
pub2.send("4")
pub3.send("5")
pub4.send("A")   // Zipped: 1, 4, 5, A

应用场景:

当你想要确保所有的发布者都发出值,并在它们发出值时进行一些操作时,zip 是一个有用的操作符。例如,合并用户的用户名和密码进行认证