atte FeS【Go・Swift開発編】での発表資料に加筆・修正をしたものです。 http://mercari.connpass.com/event/29506/
アッテ開発の技術SwiftとRxSwift⼤庭 慎⼀郎株式会社メルカリ / 株式会社ソウゾウ2016/4/18atte FeS【Go・Swift開発編】1
View Slide
⾃⼰紹介2⼤庭 慎⼀郎 ooba / bricklife株式会社メルカリに2013年4⽉⼊社現在は株式会社ソウゾウへ出向中「メルカリ」iOS版の⽴ち上げ「メルカリ アッテ」iOS版の⽴ち上げ
ϝϧΧϦΞος3ʮͳΜͰืूͰ͖ΔɹҬίϛϡχςΟΞϓϦʯiOS 8Ҏ߱ରԠSwift 2.2Ͱઈࢍ։ൃதRxSwiftΛશ໘࠾༻
iOS版開発の歴史4できごと メンバー2015年10⽉ ソウゾウに出向モック作成開始ライブラリ&設計検討開始111⽉ RxSwift採⽤決定本実装開始合宿112⽉ 幻の初サブミット 12016年1⽉ 孤独な⼀⼈開発から脱出 22⽉ 紹介制で公開 33⽉ 正式オープン 44⽉ Go Boldに開発中 4.5
なぜiOS 8以降か
なぜiOS 8以降か62015年10⽉のタイミングでiOS 7のシェアはわずかiOS 8と7とではSDKが⼤きく違う実装スピード優先Carthageが使いたかった
なぜSwiftか7
なぜSwiftか8アッテは新規プロジェクトメルカリiOS版の資産はほぼ使えない⻑くメンテナンスするコードになるいまSwift採⽤しないでいつ採⽤する?⼈材募集効果も期待
Swiftでないとできないこと9型安全、Optional、enum、etc.APIKitやHimotokiなど⽇本製のイケてるライブラリを使える• しかしAPIKitはJSON-RPC 2.0と相性が悪かったので泣く泣く不採⽤• 同じ思想でJSONRPCKitというのを⾃作した
JSONRPCKit10struct Like: RequestType {typealias Response = LikeResultlet offerId: Int64var method: String {return "LikeService.Like"}var params: AnyObject? {return ["offer_id": NSNumber(longLong: offerId)]}}{id: “1”,jsonrpc: “2.0",method: “LikeService.Like",params: {“offer_id”: 123456;}}
API側の実装11type LikeParams struct {OfferId int64 `json:"offer_id"`}
なぜRxSwiftか
その前に
なぜリアクティブプログラミングか
なぜリアクティブプログラミングか15メルカリiOS版では、Objective-Cでリアクティブプログラミングを実現するReactiveCocoaをヘビーに使っていたもうリアクティブプログラミングなしにはプログラムが組めない!
リアクティブプログラミングとは
リアクティブプログラミングとは17変なこと⾔うとマサカリが⾶んで来るので説明割愛
リアクティブプログラミングのメリット18様々な同期処理や⾮同期処理を「ストリームをどう扱うか」という視点から「統⼀的」にかつ「宣⾔的」に記述できる
リアクティブプログラミングが提供するもの191. ストリームを⽣成する⽅法2. ストリームを加⼯する⽅法3. ストリームを監視する⽅法
これがストリームだ!20どちらかの発⽣によってストリームが終わる完了エラーデータ時間開始 or↑この図を「マーブル図」という
ストリームの⽣成21⽂字列、配列、KVO、UIイベント、ネットワーク通信、デリゲートメソッド呼び出し、など、なんでもストリームにできる
配列のストリーム化22 [0, 1, 2, 3]
タップのストリーム化23タップ ダブルタップ タップ
テキスト⼊⼒のストリーム化24" "#$"# "#A B C Delete
ネットワーク通信のストリーム化25ϦΫΤετ ड৴த ड৴ྃதϨεϙϯε
26https://gist.github.com/staltz/868e7e9bc2a7b8c1f754
ストリームの加⼯27ストリーム上のデータに対して filterしたり map したり merge したり zip したり reduce したりできるオペレータと呼ばれるcombineLatest や buffer など、時間概念があるからこそのオペレータもある
filter28 http://rxmarbles.com/#filter
map29 http://rxmarbles.com/#map
merge30 http://rxmarbles.com/#merge
zip31 http://rxmarbles.com/#zip
reduce32 http://rxmarbles.com/#reduce
combineLatest33 http://rxmarbles.com/#combineLatest
buffer34http://reactivex.io/documentation/operators/buffer.html
オペレータを組み合わせた例:ダブルタップ35 https://gist.github.com/staltz/868e7e9bc2a7b8c1f754
ストリームを使ってできること36リスト処理⾮同期イベント処理データバインディングPromiseMVVM, etc.
例:テキストフィールドの変更をラベルに⾃動反映37textField.rx_text.map { "ʮ\($0)ʯ" }.bindTo(label.rx_text).addDisposableTo(disposeBag)
例:条件を満たすまでボタンを押せないようにする38let textValidation = textField.rx_text.map { !$0.isEmpty }Observable.combineLatest(textValidation,loading.asObservable()) { text, loading inreturn text && !loading}.bindTo(submitButton.rx_enabled).addDisposableTo(disposeBag)
例:インクリメンタルサーチ39textField.rx_text.debounce(0.5, scheduler: MainScheduler.instance).distinctUntilChanged().map { query -> Observable<[Item]> inif query.isEmpty {return Observable.just([])}let request = GetItemsRequest(query: query)return API.responseFrom(request)}.switchLatest().subscribeNext { [weak self] items inprint("next: \(items.count)")self?.items = itemsself?.tableView.reloadData()}.addDisposableTo(disposeBag)
アッテの実例:画像アップロード後の投稿40画像のアップロードと投稿は別API画像アップロードAPIで画像をアップロードするとメディアIDが発⾏される投稿APIにはメディアIDの配列を渡す
すべての画像をアップロード後の新規投稿41combineLatest()ը૾̍ը૾̎ը૾̏ը૾̐
⼀部の画像を再アップロード後の編集投稿42combineLatest()ը૾̍ը૾̎ը૾̏ը૾̐
アッテの実例:新規投稿・編集投稿のコード43class Photo {var image: UIImagevar mediaId: String?}var request = createUpdateRequest()photos.map { photo -> Observable inif let mediaId = photo.mediaId {return Observable.just(mediaId)}return ImageUploader.uploadImage(photo.image)}.combineLatest { $0 }.map { mediaIds -> Observable inrequest.mediaIds = mediaIdsreturn APIClient.sharedClient.responseFrom(request)}.switchLatest().subscribe(// ߘAPIͷ݁ՌΛॲཧ).addDisposableTo(disposeBag)
Swiftにおけるリアクティブプログラミング
Swiftにおけるリアクティブプログラミング452015年10⽉時点での選択肢• ReactiveCocoa• RxSwift• ReactKit
検討中の発表46https://speakerdeck.com/bricklife/swift-2-dot-0derxswift-reactkit-reactivecocoawoshi-tutemita
RxSwiftのメリット その148RxSwiftとはMicrosoftが2011年にリリースしたReactive ExtensionsのSwift版どの⾔語でもほぼ同じ仕様なので、約5年分の資産があるRxSwiftは正式にReactiveXへ取り込まれた開発やコミュニティが活発
RxSwiftのメリット その249他⾔語でRxをしていた⼈は取り組みやすい今後他⾔語でRxをやるときに経験が活かせるAndroidではRxJavaがデファクトスタンダードなので設計が共有できる?
ReactiveCocoaとReactKitの評価50ReactiveCocoaは2015年の時点ではまだα版で、Readme.mdに書かれているサンプルすらコンパイルできない状況…ReactKitは機能的に不⾜を感じた
vs ReactiveCocoa現⾏版51いまはReactiveCocoaもかなり成熟特徴• Cold ObservableとHot Observableを明確にクラスで分けている(SignalとSignalProducer)• エラーに型がある• コードがきれいらしい(伝聞)どこかでちゃんと使ってみたい
RxSwiftのデメリット
RxSwiftのデメリット53RxSwift固有のデメリットはいまのところあまり感じない強いて⾔えばReactiveCocoaの特徴の反対• Cold ObservableとHot Observableを混合• エラーに型がない
リアクティブプログラミングのデメリット54学習コストが⾼い設計に⼤きく影響(特にMVVM)ライブラリが巨⼤もし開発が⽌まったらどうする?頼りきっているとプログラミング能⼒が衰える?
チームへの浸透
有益な資料56【翻訳】あなたが求めていたリアクティブプログラミング⼊⾨http://ninjinkun.hatenablog.com/entry/introrxjaRxMarbleshttp://rxmarbles.com公式ドキュメント(以下は有志の⽇本語版)https://github.com/tid-kijyun/RxSwift/wiki
チームへの浸透57前述のドキュメント既存コード実装パターンの共有いい実装にはRPで をつけるとにかくRxに触れる機会を増やす
とにかくRxに触れる機会を増やす58社内Slackに#tech-rxというRx全般の話をするチャンネルを設置して、気軽に情報共有や相談をできるようにしているReactive Swift Meetupの企画RxSwift勉強会への参加ズンドコキヨシ with RxSwift
⼀緒に川遊びしましょう!