在 swift 中创建弱 selectors/functions

Create weak selectors/functions in swift

我在一个项目中使用 RxSwift,我发现当我直接绑定到一个选择器时,它会捕获来自自身的强引用并且 deinit 没有被调用。

我想知道如何让 selector/func 只处理一个 weak 的 self 引用。

viewModel.title
  .drive(onNext: updateTitle)
  .disposed(by: disposeBag)

func updateTitle(_ title: String) {
  navigationItem.title = title
}

我试过的是

func updateTitle(_ title: String) {
  weak var weakSelf = self
  weakSelf?.navigationItem.title = title
}

但是 deinit 仍然没有被调用。


当然,一种解决方案是完全删除 function

viewModel.title
  .drive(onNext: { [weak self] title in 
    self?.updateTitle(title)
  )
  .disposed(by: disposeBag)

但我不想失去简洁的绑定代码。

经过一番观察,显然你不能让一个 func 变弱,因为它没有保存在内存中,另一方面,闭包捕获它周围的环境。

所以我的解决方案是创建一个闭包作为 var:

viewModel.title
  .drive(onNext: updateTitle)
  .disposed(by: disposeBag)

lazy var updateTitle: ((String) -> Void)? = { [weak self] _ in
  self?.navigationItem.title = [=10=]
}

这是一个解决方案,但仍然好奇我们是否可以让选择器捕获弱引用。

玩弄它,我发现您可以获得如下语法:

viewModel.title
  .drive(onNext: weakCapture(self, method: YourViewController.updateTitle))
  .disposed(by: disposeBag)

药比病痛,还算有点意思。下面是辅助方法的定义:

func weakCapture<T: AnyObject, A1>(
    _ target: T,
    method: @escaping (T) -> (A1) -> Void
) -> (A1) -> Void {
    return { [weak target] arg in
        guard let strongTarget = target else { return }
        method(strongTarget)(arg)
    }
}

这是一个用法示例:

var c: C? = C()
let weaklyCapturedFooMethod = weakCapture(c!, method: C.foo)

weaklyCapturedFooMethod(123) // Runs foo(i: 123)
print(c as Any)
c = nil

weaklyCapturedFooMethod(123) // does nothing

不太好看。 :P

我建议只使用:{ [weak self] self?.updateTitle([=13=]) }