少しでも英語に慣れるため、タイトルのみ英語にて失礼します。
tl;dr
RxSwiftを使うと
- delegateを複数もてた
- UITableViewを簡単に実装できた
- ただ要勉強
Motivation
新しいことを始める上で、まだ試したことのないRxSwiftを触ってみたくなった、というのと、JINSMEME関連のサンプルを作るたびにあたらしいリポジトリを立てるにしても、接続部分とか毎回同じソースをコピペするのもなんだかなと思い、ベースになるようなプロジェクトを作りたいと思っていたので、JINSMEMESamplerなんて横行な名前で両者を混ぜて作ってみました。
Github
https://github.com/mitolog/JINSMEMESampler
※ Work In Progressなリポジトリですので、参加大歓迎です.
What's RxSwift?
RxSwiftというのは、非同期なイベントベースのプログラムを作る上で、複数のObservable(監視可能)オブジェクトを作成し、それらを時系列で管理して、ViewとModelのbindingを楽にすることができるライブラリです。
より細かい説明は、英語ですが、Getting Startedが勉強になります。
Project concept diagram
SDKでは主にMEMELib
というクラスがJINS MEMEとのインターフェースとなっていて、
- JINS MEMEと接続/接続解除
- Delegateプロトコルでデータを受け取る
- JINS MEMEのメタ情報(Firmwareのversionとか)を取得する
といった機能を提供しています。
本プロジェクトでは、MEMELib
シングルトンのプロキシインスタンス(MEMELibAccess.swift)を作成し、そのインスタンスがJINS MEMEからのデータを受け取り、各sampleファイルがそのデータにアクセスするという形をとっています。
※ DelegateProxyという使い方でextensionを書けるみたいですが、うまくいかなかったので、重複するようで嫌ですが一旦シングルトンのプロキシインスタンスを作っています。
Pros using RxSwift
Multiple Delegates
MEMELib
クラスはDelegateプロトコルを介して、データを受け渡します。
しかし、Delegateプロトコルは、同時に1つのインスタンスにしか適用できません。
なので、複数の箇所でデータを利用したい場合、
- 都度delegateを変更する
- KVOを利用する
- delegateチェーンを作る
- Notificationを利用する
といった手法を取らなければいけませんでした。いずれにしても、余分なコードが増えて可読性が悪くなったり、クラス同士の結合度があがったり、メモリリークの温床となったりして、導入するには躊躇してしまうようなものでした。
それを、RxSwiftのPublishSubject()
という機能を使うことで、簡単に且つ安全に?複数のdelegateを持つ振る舞いを実装することができました
具体的には、まずMEMELibAccess.swift
をSingletonにし、delegateのプロキシインスタンスのようになってもらいます。そして、そのdelegateメソッドの中でPublishSubjectのイベントを発火する。
class MEMELibAccess: NSObject, MEMELibDelegate {
static let sharedInstance = MEMELibAccess()
var rx_memeConnected = PublishSubject<CBPeripheral>()
// 中略
func memePeripheralConnected(peripheral: CBPeripheral!) {
self.rx_memeConnected.on(.Next(peripheral))
}
}
すると、それを監視していたObserverにイベントが流れる。
MEMELibAccess.sharedInstance.rx_memeConnected.subscribeNext { [unowned self] peripheral in
print("meme connected")
self.scanBtn.enabled = false
self.tableView.userInteractionEnabled = false
// go to next view
self.performSegueWithIdentifier("SampleListSegue", sender: self)
}.addDisposableTo(self.disposeBag)
という寸法です。
Info: How PublishSubject works in this sample
ReactiveXな世界ではSubject
というやつは監視する側(Observer)にもなれるし、監視される側(Observable)にもなれる機能を持っていますが、ここではObservableとしての機能のみ利用しています。
以下の概念図をみるとイメージしやすいのですが、1番上の資格で囲ったシーケンスがMEMELibAccess.swiftのdelegate
メソッドの時系列だと考えてください。
そのすぐ下が、例えばScanViewController.swift
上の時系列と考えてください(一番下は無視)。
この時、それぞれの時系列は独立しています。
で、この概念図でいくと、ScanViewController.swiftでは**MEMELibAccess.sharedInstance.rx_memeConnected.subscribeNext
した時点から**、delegateメソッドのObservableをウォッチし始めます。
これは、ほぼKVOの動きと同じですが、KVOを実装するよりもコード量も少なく、断然扱いやすく感じます。
画像: RxSwiftのPlaygroundより
参考: http://reactivex.io/documentation/subject.html
UITableView+Rx is so powerful
いつもなら、UITableViewのdelegate,dataSourceメソッドを実装して~ってやりますが、そういうのが必要ありません。例えば、ScanViewController.swiftで実装しているUITableView関連の処理は以下のみです。
viewModel.peripherals.bindTo(self.tableView.rx_itemsWithCellIdentifier("PeripheralCell")) { _, peripheral, cell -> Void in
cell.textLabel?.text = peripheral.identifier.UUIDString
}.addDisposableTo(self.disposeBag)
// tableview did selected
self.tableView.rx_itemSelected.subscribeNext { [unowned self] indexPath in
let peripheral = self.viewModel.peripherals.value[indexPath.row]
MEMELibAccess.connect(peripheral)
}.addDisposableTo(self.disposeBag)
上記は、いわゆるcellForRow~のメソッドと、didSelect~のメソッドに相当します。とてもすっきりしたように感じます。しかも、いつも書いていた、プロトコル準拠の宣言すら書いていません。
Cons using RxSwift
Hard to understand its source code
概念を勉強するだけなら
http://reactivex.io/
や
https://github.com/ReactiveX/RxSwift
あたりを見ればいいのですが、いざ実際にプロジェクトに組み込もうとすると、様々なRxSwiftの様々な機能を使っていかなければいけません。
その際、ソースを掘っていくと、結構意味不明な文法が多用されていて、はて....と手が止まってしまいます。しかもソースも膨大で、堀れすぎてしまい元に戻るのが大変です。
逆にいうとそういうハイレベルなswiftを読めるので全体的なSwift力の底上げにはつながりますが、そのたびにgoogleさんに聞くので非常に時間がかかります。ただ、元々の知識量と思いますので、個人差の問題かもしれません。
Is it safe?
RxSwift初心者的には、ブラックボックスが大きすぎて、自分のしていることがナンセンスなことかそうじゃないかの見分けがつきません...なので、今自分がしていることでリークが起きていないかいつもビクビクしています。特にdisposebagあたりの実装が完全に理解できていないので、これは勉強しておく必要があるかと思いました。
Summarize
RxSwiftを使うと
- delegateを複数もてた
- UITableViewを簡単に実装できた
- ただ要勉強
ということで、JINS MEMEの以後のサンプルでもなるべくRxSwiftで書いてみようと思います。なるべく。
Reference
RxSwiftを使ってGitHubのおすすめユーザーを表示するアプリをつくってみた
Implementing MVVM in iOS with RxSwift
あと、RxSwiftのplaygroundは非常に勉強になります。