speakerdeckのiosビューアを作ろうとして途中で諦めた話

アプリ作成は途中で諦めたけど、折角なのでソースコードと開発中のあれこれを書いておこうという記事です。

## 先にまとめ

- speakerdeckのiosビューアが欲しくて自作してた
- speakerdeckの画像のDLが遅くてまともに使えなかったので諦めた
- RxSwiftとReSwiftの勉強にはなって良かった

### ソースコード

- アプリ本体: https://github.com/abeyuya/Slive
- スライド描画UIライブラリ: https://github.com/abeyuya/SlideViewer

## 作りたかったもの

↓こういうやつ
<img width="866" alt="screenshot.png" src="https://github.com/abeyuya/SlideViewer/raw/master/doc/slideviewer.gif">

タイトルの通り、speakerdeckのiosビューアが欲しかった。
普段はiPhoneを使っていて、はてぶアプリとかでspeakerdeckの記事を見かけて読むことがちょいちょいある。
その際webviewだとスライド小さいし、レスポンス悪いし、横にしてもサイズ合わないしで、見づらくて不満だった。
safariで開いても同じく。

なので勝手にネイティブのビューアを作って見やすくしようというのがモチベーションの半分。
ReactNativeとRxSwiftとReSwiftに興味があって使ってみたかったのが残りの半分。


## 開発時の紆余曲折

読み飛ばし推奨

- speakerdeckアプリ欲しい！
- ReactNative触りたい！
- よし！ReactNativeでspeakerdeckビューア作ろう！
- ReactNativeで開発し始めた
- この記事とかを参考にして、pdfファイルをスクレイピングで取得する方針で検討
    - https://qiita.com/natmark/items/b8267125983218774400
- ReactNativeでいい感じのPDFビューアが無かった
- その他のエラーも出て大変だったので、ReactNative諦めてSwiftにしよう
- Swiftでもいい感じのPDFビューアが無かった
- よし！こうなったらPDFビューアライブラリも作ろう！
- せっかくだから気になってたReSwiftを使おう！
- ざっくり動くところまでできた
- speakerdeckからPDF取ってきたらめっちゃDL遅い
- これじゃ使い物にならない... orz
- speakerdeckのHTML見てたら描画しているのは画像ファイルだった
- 画像を順次DLして描画すればだいぶマシになりそう
- PDFビューアライブラリに画像ビューア機能も入れて、ちょっと汎用的なスライドビューアライブラリに進化した！
- アプリ本体側にspeakerdeckから画像リストをスクレイピングする処理を実装
    - speakerdeckはiframeとか使っててちょっと面倒だった
- 画像のURLリストから随時描画するようにした
- 画像1枚のDLもめっちゃ遅いやん...
- これ以上頑張っても結局欲しいもの作れないなぁ...
- イマココ

## SlideViewer

開発してたスライドビューアライブラリがこれ。
https://github.com/abeyuya/SlideViewer


SlideShareのiOSアプリがスライドビューアとしては結構使いやすいと思ったので、あのUIを完コピするぜーという方針で開発した。
(そういうUIのライブラリを探したけど見つからなかった。)
紆余曲折に書いた通り、当初はPDFビューアとして実装したけど、途中で画像リストのビューアの機能も持たせた。

## ReSwift

上記のSlideViewerにはReSwiftを導入した。
使ってみたいドリブンで採用したが、結果的にはライブラリの特徴と結構相性が良くて、採用して良かったなぁと感じた。

### 良かった点

#### 1. 複雑な状態をシンプルに管理できた

このライブラリではスライドの現在位置、サムネイルの現在位置、メニュー表示の有無、端末の縦横などの状態の組み合わせによって画面を描画するので、普通に実装すると結構複雑なコードになりそうだった。

ReSwiftのおかげでこれらの状態の変更通知、通知の受信を一方通行で書くことができてだいぶスッキリ見通しの良いコードになった気がする。

#### 2. ViewController間の依存を減らせた

今回のアプリだと、スライドを横スワイプして次のスライドに遷移した時に、横に表示しているサムネイルも合わせて遷移させたかった。
普通に書くなら、ViewControllerから別のViewControllerのメソッドを呼び出して遷移の通知をしたり、delegateを使ったり、Notificationを使ったりするかなーと考える。

ReSwiftだとdispatchを発行すればOKで、他のViewControllerのことを知らなくて良いので、依存関係が減らせてよかった。
Notificationとほぼ同じ用途だったんだけど、上手く言えないけどNotificationより使い勝手が良い感じがした。

### 悪そうな点

あんまり小規模な要件だと無駄に複雑になって逆効果かなーとは思った。
とはいえこのライブラリ程度の規模感でも恩恵を感じたので、結構どの案件でも使える気がする。

仕事で開発しているアプリにも導入して恩恵を受けるイメージは沸くし、部分的に導入も簡単にできそうな気がしている。


仕事とかで導入するなら開発メンバーにreduxを覚えてもらわないといけないので、そのreduxの学習コストも多少気になる。
自分はjsで触っていたのでスルッと使えたが、初めてのreduxだと概念を理解するのに少しだけコストはかかりそう。


## Slive

上記のライブラリを組み込んで実際にアプリとして開発をしていたのがこれ。
https://github.com/abeyuya/Slive

具体的にはspeakerdeckをスクレイピングして、画像URLのリストを取得する処理とかを書いていた。
このURLリストを上記のビューアライブラリに渡す。


## RxSwift

アプリ本体にはRxSwiftを導入してみた。
これも使ってみたいドリブンで入れてみたけど、結構良かった。


### 良かった点

RxはjavascriptのPromiseみたいなちょっとすごいやつ、という印象だった。

iOSのコード書いていると、selectorだったりdelegateだったりで強制的に処理が分割されていくので、どうしても見通しが悪くなるんだけど、それを一連の流れで表現できるのが良かった。

あとはjavascript同様にcallback地獄になりがちだけど、それをPromiseっぽい感じでネストさせずに表現できるのが良かった。

最初Observableって何ぞやと思ったけど、javascriptのPromise的なやつと認識したらだいぶ理解が楽になったような気がする。


### 悪かった点

ReSwiftと同じく学習コストはちょっとかかりそう。
あと、便利だなーと思いつつもReSwiftほど恩恵は感じなかった。
「無くても良くない？」と言われたら、「まあですねー」となってしまう感。
どういうアプリだとより効果的なんだろうか。


## 今後

chrome developer toolで見てたら、画像1枚DLするのに6秒くらいかかっていることがわかって、これ以上の改善は大変だなーと思い、一旦開発を諦めている。
画像はS3にホストされているんだけど、CloudFront挟んでくれてたらなぁ...

[この記事](https://qiita.com/smith_30/items/e0cba3cf0348bd1f87bf)を読んでみたら、アプリで画像のDL順を適切にハンドリングすることでwebで閲覧するよりはマシ、というものは作れそうではある。

とはいえ画像1枚DLするのに6秒なので、まともに使えるものにはならない気がしている。

## KPT

- Keep
    - ReactNative, ReSwift, RxSwiftを触れた / とりあえずは書けるようになった
- Problem
    - 趣味開発とはいえ、もうちょいspeakerdeckの挙動をちゃんと調べてから計画的に開発しても良かったかも
- Try
    - 次何作ろうかなー