Combine 学习笔记(五):Cancellable

在实际开发中,当 Subscriber 在某个时候不想接收 Publisher 发布的数据时,可以取消订阅以释放资源。Combine 中提供了 Cancellable 协议,该协议中定义了一个 cancel 方法,用于取消订阅流程。Cancellable 的定义如下:

protocol Cancellable {
    func cancel()
}

Combine 中还定义了一个 AnyCancellable 类,实现了 Cancellable 协议,特点是会在该类析构时自动执行 cancel 方法,定义如下:

final public class AnyCancellable : Cancellable, Hashable {
}

extension AnyCancellable {
    // 将AnyCancellable对象存储在某个集合中
    final public func store(in set: inout Set<AnyCancellable>)
}

前面讨论的 sink 和 assign 的返回值都是 AnyCancellable,所以它们都可以调用 cancel 方法来取消订阅。当 AnyCancellable 所在的类执行析构函数时,AnyCancellable 的析构函数也会被触发。

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对象被释放后,整个订阅流程也会随之结束,所以在实际开发中需要把这个对象用一个变量接收。上面的例子的第六行代码就用 subscription 这个变量来接收 AnyCancellable 对象或存储到 Set<AnyCancellable> 中。

可以理解为 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() //取消网络请求

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注