Swift Combine — AnyCancellable的理解与使用

SwiftCombine框架中,AnyCancellable是一个非常重要的类型,用于持有和管理订阅关系。它可以持有任何类型的Cancellable对象,并提供了一种类型擦除的方式来管理订阅关系。

首先看一下AnyCancellable的定义:

final public class AnyCancellable : Cancellable, Hashable { 
	final public func cancel()
}

public protocol Cancellable {
    func cancel()
}

AnyCancellable是一个class类型,继承了Cancellable协议并实现了cancel方法。cancel方式是用来取消订阅的,也就是断开PublisherSubscriber的联系,从而不再接受Publisher的任何事件。

另外特别要强调的是AnyCancellable实例在deinit时(即销毁时)时自动调用cancel()。

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

class AnyCancellableViewModel: ObservableObject {

  let publisher = PassthroughSubject<String, Never>()
  var subScription: AnyCancellable?

  init() {
    setUpSubscription()
  }

  func setUpSubscription() {
    subScription = publisher
      .sink { value in
        print("Received value: \(value)")
      }
  }

  func sendMessage() {
    publisher.send("text")
  }

  func cancelSubscription() {
    print("Subscription cancelled")
    subScription?.cancel()
  }
}

在上面代码中,在AnyCancellableViewModel类中定义了一个PassthroughSubject类型的publisher和一个AnyCancellable类型的subScription

在方法setUpSubscription()中,通过sink方法订阅Publisher,并将sink方法返回的对象用subScription属性持有,如果不持有,那么出了方法作用域订阅就失效了,持有的话后期不需要的时候也可以取消订阅,比如在cancelSubscription()方法中,就调用cancel()方法取消订阅。
在这里插入图片描述
上面效果中,连续调用send方法,不断地有输出,当调用cancel方法后,再次调用send方法,就没有输出了。

完整代码如下:

class AnyCancellableViewModel: ObservableObject {

  let publisher = PassthroughSubject<String, Never>()
  var subScription: AnyCancellable?

  init() {
    setUpSubscription()
  }

  func setUpSubscription() {
    subScription = publisher
      .sink { value in
        print("Received value: \(value)")
      }
  }

  func sendMessage() {
    publisher.send("text")
  }

  func cancelSubscription() {
    print("Subscription cancelled")
    subScription?.cancel()
  }
}

struct AnyCancellableDemo: View {
  @StateObject private var viewModel = AnyCancellableViewModel()

  var body: some View {
    VStack {
      Button("Send text") {
        viewModel.sendMessage()
      }

      Button("Cancel subscription") {
        viewModel.cancelSubscription()
      }
    }
    .buttonStyle(BorderedProminentButtonStyle())
  }
}

viewModel为界面持有,当界面销毁的时候,viewModel也就销毁了,继而AnyCancellable实例对象也就销毁了,销毁时自动调用cancel方法,取消订阅。

cancelSubscription()方法中,如果直接将subScription设置为nil,同样有调用cancel方法的效果。

当有一个Publisher的时候,可以用一个AnyCancellable实例对象去持有订阅,那么如果有多个Publisher的时候,定义很多个AnyCancellable实例对象有点说不过去了,这时候就要用到AnyCancellable的下面这个方法了。

extension AnyCancellable {
    final public func store(in set: inout Set<AnyCancellable>)
}

store(in:)方法接受一个AnyCancellable类型的集合,而这个集合就是用来存储订阅的,下面修改一下上面的代码。

class AnyCancellableViewModel: ObservableObject {

  let publisher = PassthroughSubject<String, Never>()
//  var subScription: AnyCancellable?
  private var cancellable = Set<AnyCancellable>() // 1

  init() {
    setUpSubscription()
  }

  func setUpSubscription() {
  	// 2
    publisher
      .sink { value in
        print("Received value: \(value)")
      }
      .store(in: &cancellable)
  }

  func sendMessage() {
    publisher.send("text")
  }

  func cancelSubscription() {
    print("Subscription cancelled")
//    subScription?.cancel()
	// 3
    cancellable.removeAll()
  }
}

首先定义一个AnyCancellable类型的集合cancellable,然后在sink方法订阅的时候调用store(in:)方法,将订阅存储到cancellable集合中,最后如果取消订阅的话,调用cancellable.removeAll()方法。
这样如果有两个或者更多个Publisher都是可以存到cancellable集合中。

总之 AnyCancellable是一种管理订阅状态的工具,能根据开发者需要在某个时段切断 PublisherSubscriber的联系。

最后,希望能够帮助到有需要的朋友,如果觉得有帮助,还望点个赞,添加个关注,笔者也会不断地努力,写出更多更好用的文章。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值