如何扩展 Combine:以给 UIButton 设置 title 为例

我的 PasteNow 用了 Apple 自带的 Combine 库来实现一些响应式的设计,因为之前有 RxSwift 的使用经验,因此上手 Combine 比较快,加上是系统自带的,用起来也非常顺手。于是我最近还在做另外一件事情:迁移其他旧项目的 RxSwift 代码至 Combine。因为 Combine 作为 iOS 13/macOS 10.15 就引入的系统库,现在已经到了可以普遍采用的程度了,是时候和 RxSwift 说再见了。

毕竟 RxSwift 发展了那么多年,生态还是比 Combine 要丰富一些。于是在从 RxSwift 迁移至 Combine 的过程中,我遇到了不少 RxSwift 可以非常方便做到的事情,但在 Combine 默认不太方便。好在我们可以去扩展 Combine,就让我用一个 UIButton 设置 title 的例子来说明这个吧。

比如 RxSwift 里可以非常方便地将一个值绑定到 UIButton 上去:

.bind(to: button.rx.title(for: .normal))

在 Combine 里面,就只能:

.sink(receiveValue: { title in
        button.setTitle(title, for: .normal)
})

如果这个 button 还是 self 上的,那么还得麻烦来一个 weak self,不然会强引用。

.sink(receiveValue: { [weak self] title in
        self?.button.setTitle(title, for: .normal)
})

真的是非常麻烦呢。但只需要写这样的一个扩展,就能轻松解决这个问题:

import UIKit
import Combine

extension Publisher where Self.Output == String, Self.Failure == Never {

    public func setTitle(on button: UIButton, state: UIControl.State) -> AnyCancellable {
        sink { title in
            button.setTitle(title, for: state)
        }
    }

}

然后就可以快乐地这样调用了:

.setTitle(on: button, state: .normal)

希望这则小技巧可以帮助到你,欢迎交流讨论。

欢迎使用图拉鼎和他的团队开发的作品

One Switch - 多功能开关工具

常驻 macOS 菜单栏的开关工具,可以快速开关 AirPods、睡眠模式、切换黑暗模式等。

No Comment

Leave a Comment