Swift中發佈-訂閱框架Combine的使用

Combine簡介
Combine是一個蘋果用來處理事件的新的響應式框架,支持iOS 13及以上版本。
你可以使用Combine去統一和簡化在處理類似於target-action,delegate,kvo等事情的代碼。
iOS目前已經有第三方的響應式框架了,如:RxSwift、ReactiveCocoa,但是蘋果現在發佈了自己的新的框架。
它提供了一種聲明式、函數式的編程方式,可以讓開發者更加簡單、高效地處理異步數據流。

Combine核心概念
Combine的核心概念是Publisher、Subscriber和Operator。發佈者,訂閱者和中間操作者。
發佈者Publisher:可以將值或錯誤發送給訂閱者,並且在完成或取消時,向訂閱者發送相應的消息。
訂閱者Subscriber:接收發布者發送的值、錯誤和完成信息,並進行相應的處理。
操作符Operator:用來對數據流進行轉換、過濾、合併等處理,Combine框架中提供了很多操作符,例如map、filter、merge等。

當一個Publisher發佈一個事件時,Subscriber會被通知這個事件,並執行相應的操作。
一個Subscriber可以訂閱多個Publisher,並且每個Publisher都可以同時擁有多個Subscriber。當所有的Subscriber都取消訂閱時,Publisher會停止發佈事件。
Operator可以對事件流進行各種操作,包括數據轉換、過濾、組合等。比如,map操作可以將一個事件流中的元素轉換成另一個類型,filter操作可以過濾出符合條件的元素,merge操作可以將多個事件流合併成一個事件流等。
 
map操作符可以將數據流中的值進行轉換,返回一個新的數據流。例如,將一個字符串轉換成大寫形式:
let stringPublisher = Just("hello, world!")
let uppercasedPublisher = stringPublisher.map { $0.uppercased() }
filter對數據流中的值進行過濾,返回一個新的數據流。例如,過濾掉數組中的偶數:
let arrayPublisher = [1, 2, 3, 4, 5].publisher
let oddPublisher = arrayPublisher.filter { $0 % 2 != 0 }
merge對數據流進行合併,生成一個數據流。例如,將兩個發佈者合併成一個:
let publisher1 = Just("hello")
let publisher2 = Just("world")
let mergedPublisher = Publishers.Merge(publisher1, publisher2)
下面是一個簡單的例子,展示瞭如何使用Combine來監聽一個UITextField的文本輸入
import UIKit
import Combine

class ViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!

    var cancellables = Set<AnyCancellable>()

    override func viewDidLoad() {
        super.viewDidLoad()

        // 創建一個訂閱者,打印出文本輸入的內容
        let subscriber = Subscribers.Assign(object: self.textField, keyPath: \.text)

        // 訂閱文本輸入框的文本變化事件
        self.textField.textPublisher(for: .editingChanged)
            .map { $0.text ?? "" }
            .subscribe(subscriber)
            .store(in: &cancellables)
    }
}

extension UITextField {
    func textPublisher() -> AnyPublisher<String, Never>
    {
        NotificationCenter.default
            .publisher(for: UITextField.textDidChangeNotification, object: self)
            .map {($0.object as? UITextField)?.text  ?? ""}
            .eraseToAnyPublisher()
    }
}

 

AnyCancellable
Combine 中還定義了一個 AnyCancellable 類,實現了 Cancellable 協議,特點是會在該類析構時自動執行 cancel 方法。

在實際開發中,當 Subscriber 在某個時候不想接收 Publisher 發佈的數據時,可以取消訂閱以釋放資源。
Combine 中提供了 Cancellable 協議,該協議中定義了一個 cancel 方法,用於取消訂閱流程。
import Combine
let subject = PassthroughSubject<String, Never>() // 創建PassthroughSubject
// 訂閱
let subscription = subject.sink(receiveCompletion: { _ in
    print("receiveCompletion")
}, receiveValue: { value in
    print(value)
    
})
// 發送數據
subject.send("hello")
// 中途取消訂閱
subscription.cancel()
// 後面發送的數據都會失敗
subject.send("world")
subject.send(completion: .finished)
/* 輸出:
 hello
 */
可以理解爲 AnyCancellable是一種管理訂閱狀態的工具,能根據開發者需要在某個時段切斷 Publisher和 Subscriber的聯繫。
AnyCancellable 的一個應用就是可以在某種情況下中斷網絡請求,實現如下:
import UIKit
import Combine
let dataPublisher = URLSession.shared.dataTaskPublisher(for: URL(string: "https://louyu.cc")!)
let cancellableSink = dataPublisher.sink { completion in
    switch completion {
    case .finished:
        break
    case .failure(let error):
        print("error: \(error)")
        break
    }
} receiveValue: { value in
    print("received \(value)")
}
cancellableSink.cancel() //取消網絡請求

參考文章地址:
https://www.jianshu.com/p/1dc27229a533
https://louyu.cc/articles/ios-swift/2021/03/?p=2865/
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章