こんにちは。開発部第1グループの涌井です。
今回は Combine Cocoa というライブラリを導入してみたというお話になります。
※ Combine Cocoa にスポットをあてたいので、以降に出てくる RxSwift や Combine の基礎知識(Subscribe や Publisher など)に関しては、割愛となっています。
開発環境
- MacOS : Venture
- 対応 iOS : 14系-16系
- Combine Cocoa : 0.4.1
導入背景
- あるアプリでは、イベント検知は RxSwift で、画面は UIKit で実装
- このアプリにおいて下記の改修を行う
- 新規機能はイベント検知を Combine で、画面は SwiftUI で実装
- 既存機能は、画面は UIKit のままで、イベント検知は Combine に置き換え
- 既存機能の改修は、機能は動作的に問題ないので、なるべくロジック変更なしで、工数を抑えたい
ポイント
- イベント検知の実装方法を RxSwift → Combine に変更
- 工数を抑えたい(既存機能の改修影響も抑えたい)
そんなことできるの?という感じですが、できるんですよ。Combine Cocoa ならね。
ともったいつけてきたわけですが、そもそも Combine Cocoaとはなんぞや。
Combine Cocoa とは
超ざっくりいうと、UIKitのイベント処理に対して Combine の Publisher を実装してくれているライブラリです。
https://github.com/CombineCommunity/CombineCocoa
Publisher を提供している箇所は、下記画像の赤枠内のような構成になっています。
流石にざっくりすぎるので
- RxSwift での UIButton のタップ処理のイベント購読コード例
- Combine のイベント購読コード例
を踏まえて、Combine Cocoa での実装をみていきます。
RxSwift での UIButton のタップ処理のイベント購読コード例
button.rx.tap .subscribe(onNext: {[unowned self] _ in // 何かの処理 }) .disposed(by: disposeBag)
Combine のイベント購読コード例
publisher.sink { // 何かの処理 } .store(in: &cancellables)
上の2つの例を眺めていると、Combine の購読処理は sink で行われるので、button の tap 処理と Combine の Publisher が紐づいてくれると、sink で処理できそうに見えますね。
ここで Combine Cocoa の UIButton+Combine.swift を見ると
Combine Cocoa の tapPublisher
#if !(os(iOS) && (arch(i386) || arch(arm))) import Combine import UIKit @available(iOS 13.0, *) public extension UIButton { /// A publisher emitting tap events from this button. var tapPublisher: AnyPublisher<Void, Never> { controlEventPublisher(for: .touchUpInside) } } #endif
UIButton の tap の Publisher が提供されています。つまり、button のタップ処理と Combine の Publisher が紐づいているわけです。素敵ですね。
以上を踏まえて、Combine Cocoa で置き換えしたコード例は以下のようになります。
Combine Cocoa での UIButton のタップ処理のイベント購読コード例
button.tapPublisher.sink { // 何かの処理 } .store(in: &cancellables)
これだけです。素敵ですね。
置き換え前後の差分比較すると、コードの構造的に大きな変更もなく、置き換えによる影響は抑えられているように思います。
また例では UIButton を挙げましたが、UIGestureRecognizer などもあり、色々な Publisher が提供されているので、置き換えは Combine Cocoa で賄えました。素敵ですね。
まとめ
- Combine Cocoa を使うと、UIKIt のイベント処理に対して Combine で処理できる
- UIKit を使いつつ RxSwift から Combine へ置き換える際に、Combine Cocoa を使うと、コード変更の構造的な差分は少なく、工数がそれほどかからない
- Combine Cocoa 素敵ですね
参考記事
https://dev.classmethod.jp/articles/combinecocoa/
https://emoshu.co.jp/blog/archives/18