在实际开发中,当 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() //取消网络请求