能登 要

札幌在住のiOSアプリ開発者。SwiftUI により分割されたデバイス間を縦横にやりとりできる考え方に転換しています。

iOSアプリ開発者。2009年のiPhoneアプリ開発開始時期から活動。開発言語のアップデートの中でSwiftUIおよび周辺技術に着目中。

Combine framework+RxCombineを使ってRxAlamofire(通信ライブラリ)を置き換える

端的に云うと

RxSwiftを使った2つのサードパーティ製ライブラリに依存している通信機能を置き換える。

1) Reactiveプログラミングとライブラリ

2010年台後半にReactiveプログラミングのアイデアがiOSアプリ開発にも浸透。2020年台前半でも稼働、新規開発されているiOSアプリは多い。

Reactiveプログラミングについては以下の解説が他プログラミング手法との関係性も含めて簡潔に述べらている。

Reactive Programmingとはなんですか? - Quora

Reactiveという本来考え方からすればプログラミングとして確立した手法は"限定的"であるにせよ、プログラミングの規範を変えた(データストリーム制御主体でプログラム全体を制御する)のは違いない。

Reactiveプログラミングのためのライブラリ(ミドルウェア)としてはReactiveXが提供しているRxSwiftがある。

GitHub - ReactiveX/RxSwift: Reactive Programming in Swift

iOSアプリ開発の場合はRxSwiftを使うのが公式SDKに次いで半ば共通語彙となっている節がある。2020年前半は特に画期的な代替案が出てこないため技術的話題の熱量的には高いわけではない。

2) 通信ライブラリ

ミドルウェアに関してReactiveプログラミング以外で話題に上がることが多かったのがネットワークライブラリで、有名なものとしてはAlamofireがある。Alamofireは2010年台に重宝されていたAFNetworkingの後継ライブラリでSwift登場後、可読性とコード記述しやすさから2010年台後半にネットワークライブラリとして採用されていた。

Alamofire

通信ライブラリも前述のReactiveプログラミングと同様、技術的話題の熱量は低めとなっている。

サードパーティ通信ライブラリについての個人的見解として、2020年台においてはiOS SDKの通信機能が整備されているため、サードパーティ製の通信ライブラリが必須という状況ではないと考えている。iOS SDKもいつまでもアプリ開発時の課題をそのままにしているわけではないのだ。

サードパーティ通信ライブラリ考古学 - iPhoneアプリ開発 | Irimasu Densan Planning - いります電算企画

3) Reactiveプログラミングと通信ライブラリが合体すると?

通信ライブラリ(Alamofire)をReactiveプログラミング(RxSwift)に導入するためのライブラリがRxAlamofireである。Reactiveプログラミングと通信ライブラリの熱量が高かった頃に公開された。

GitHub - RxSwiftCommunity/RxAlamofire: RxSwift wrapper around the elegant HTTP networking in Swift Alamofire

2010年台にあった利点(可読性、コード記述しやすさ)はともかく2つのサードパーティライブラリ上に立脚するサードパーティのライブラリを使わなくても済むに越したことはないと思う。サードパーティーに立脚したサードパーティーライブラリなんて普通という話もあるが開発コミュニティの規模によるとしかいえない。 例えば、Webプログラミングで大小のサードパーティーライブラリから構成されるnodejsのようなライブラリのコミュニティに比べモバイルアプリコミュニティの規模ははるかに小さい、メンテナンス担当がふといなくなった際に代わりのメンテナンス担当が見つからず問題報告だけが山積みされるみたいな状況に陥るのはできるだけ避けたいものである。

ゆえにRxAlamofireを2020年台に積極的に採用する理由は無い様に見受けられる。

4) Combine framework+RxCombineで通信ライブラリを置き換える

以下のRxAlamofireを使ったコードをApple謹製ライブラリを使用したものの(できるだけ)置き換える。

let request = URLRequest(URL(String: "https://randomfox.ca/floof"))
let observer = URLSession.shared.rx.response(request: request)

上記コードはRxAlamofireを使ったものでURLRequestから通信結果を取得するためのObserverを取得できる。Observerは非同期でデータ取得を試みる。通信処理を途中で中断したい場合はObserverをdisposeすれば良い。

上記コードをApple謹製のライブラリCombine frameworkとサードパーティライブラリのRxCombine で置き換える。RxCombineはRxSwiftをアプリ上で継続的に使用するためのものでCombine frameworkとRxSwift間のブリッジ機能を提供する。

GitHub - CombineCommunity/RxCombine: Bi-directional type bridging between RxSwift and Apple's Combine framework

Apple謹製のライブラリCombine frameworkはSwift向けの非同期処理を宣言的に行うためのライブラリで(使用語彙に違いはあれど)RxSwiftに機能的に似たフレームワークとなっている。 Combine frameworkはiOS13 SDKから利用できるようになっている。

GitHub - CombineCommunity/rxswift-to-combine-cheatsheet: RxSwift to Apple’s Combine Cheat Sheet

Combine frameworkをiOSアプリに組み込むとiOS SDKの通信機能であるURLSessionにPublisher(RxSwiftでいうところのObserver) が提供されている。先ほど紹介したRxCombineを使うことでコードを置き換えることができる。

利用に際してRx〜のミドルウェアを追加する。Cocoapodsの場合、Podfileに以下のミドルウェアを加える。

  pod "RxSwift"
  pod "RxRelay"
  pod "RxCombine"

RxRelay はエラーが発生しえないObserverを作成するためのミドルウェア。RxCocoaがはRxRelayを内包しているためRxCocoaを既に組み込んでいるプロジェクトではpod定義を加えるまでも無いがここでは使用していることを示すためあえてRxRelay を定義した。

実際のコードは以下となる。

let request = URLRequest(url: URL(string: "https://randomfox.ca/floof")!)
URLSession.shared.dataTaskPublisher(for: request).asObservable()

Single<(data: Data, response: URLResponse, data: Data)>の形に変形する場合は以下となる。

let request = URLRequest(url: URL(string: "https://randomfox.ca/floof")!)
let single = URLSession.shared.rx.response(request: request).asSingle()

Single<(data: Data, response: HTTPURLResponse)>の形に変形する場合は以下となる。

let request = URLRequest(url: URL(string: "https://randomfox.ca/floof")!)
let single = URLSession.shared.dataTaskPublisher(for: request).asObservable().asSingle().map { output -> (Data, HTTPURLResponse) in
            let httpURLResponse = output.response as! HTTPURLResponse
            return (output.data, httpURLResponse)
        }

まとめ

iOSアプリに開発にサードパーティライブラリの導入は欠かすことができないが、サードパーティライブラリもiOS SDKの機能追加によりサードパーティライブラリが必要なくなるケースがある。Appke謹製の機能で代替できるのであればサードパーティの置き換えてサードパーティへの依存度を下げることはサードパーティの開発が中止されるといったトラブルを避けることができる。

iOS アプリ開発はプログラミング効率アップ(可読性、簡潔な記述)に重点を置いたブログ投稿が長年蓄積されたため、サードパーティライブラリの選定理由も検索上位だったから、になりがちだがAppleの同行とサードパーティライブラリのコミュニティの活状(そしてライブラリ同士の依存度も!)などをチェックも実施し、ライブラリ導入を検討した方が良いだろう。

参考