はじめに
2018年のiOSアプリ開発の振り返りとして技術記事/動画を勝手に振り返ってみます。
ランキングではなく個人的に何回か読み返した記事となります。
ですのでここにはない分かりやすく有用なTipsなんかも今年多くあったとは思うのですが、それらについては記載してません。
紹介する記事/動画については私の理解でその概要と感想を書いていますが、間違えているかもしれませんね。みなさんもし間違っていたら教えていただけるとありがたいです。
Swift.Decodable + Int64 / iOS 10 = 要注意
たぶんこんな事が書いてある
- 概要
- サーバサイドのレスポンスを内部のインスタンス化する際にエラーになった
- 新規(もしくはHimotokiからの移行?)で
Swift.Decodable
を使ってた - Int64とiOS10のデバイスでのみ再現する
- 経緯
- 1000000000000000070をInt64のidにDecodeするとiOS10デバイスでエラーする再現ができた
- SwiftはオープンソースなのでInt64のデコードでエラーがでる部分を調べた
- そのコードだけでは判定がエラーになることしかわからない
- iOS11ではNSNumberを使うところがiOS10ではNSDecimalNumberを使っているのが原因と予測
- そのコードだけでは判定がエラーになることしかわからない
- SwiftはオープンソースなのでInt64のデコードでエラーがでる部分を調べた
- 1000000000000000070をInt64のidにDecodeするとiOS10デバイスでエラーする再現ができた
- 回避策
- 結果的に値が大きいときはHimotokiを使うことにした
感想
- 1000000000000000071でエラーにならないとも書いている部分がイマイチよくわからない
- 1000000000000000070では問題ありエラー
- 1000000000000000071では問題ないらしい(なぜ値が大きくなったのに?)
- 1000000000000000080でも問題ありエラー
- そもそもこれとは別の話だけど関連性のある話題として
- アプリではユースケースとしてidなどが64bit超えの値を使いたいというのがある
- サーバサイドでidをAuto Incrementしているのだろう
- ユーザ参加型のコンテンツは数がめちゃくちゃ増えるので64bit整数が使われる- しかしアプリとしたらidはStringでサーバサイドから返ってくればいい
- レスポンスとして idはStringで返したらいいんじゃない? といつも思う
- Int64だとか考えなくて良くなるし
- しかしアプリとしたらidはStringでサーバサイドから返ってくればいい
- アプリではユースケースとしてidなどが64bit超えの値を使いたいというのがある
Storyboardとの付き合い方 2018
たぶんこんな事が書いてある
- IBDesignableのテクニックとしてモジュール分割する
- IBDesignableのプレビューのためにそのターゲットのクラスたちがビルドされ時間かかる
- モジュール分割しておけばビルド対象のコードを減らせる
- IBDesignableのプレビューのためにそのターゲットのクラスたちがビルドされ時間かかる
- スタイルの指定はクラスが行いIB上で繰り返さない
- IB上で指定しない
- IBの「User Defined Runtime Attributes」も使わない
- 画面遷移でsegueを使わずにファクトリメソッドで遷移する
- segueの値はコードでも管理しないと二重管理になってしまうから
感想
-
スタイル の指定をIBでやらないのは経験上有りだと思う
- 「User Defined Runtime Attributes」の文字列での指定はマジしんどいし
- やっぱりパラメータ指定はコンパイルエラー出してほしい
- 「User Defined Runtime Attributes」で頑張って指定できるようにしがち
- 文字列指定からスタイリングの振る舞いを決定するようなコードにしがち
- コピペミスしても気づけずコンパイルエラーにならないので困りがち
- 文字列指定からスタイリングの振る舞いを決定するようなコードにしがち
- 「User Defined Runtime Attributes」の文字列での指定はマジしんどいし
- segueの二重管理の件はR.swiftなりSwiftGen使えばStoryboardファイルからコードを生成できる
- そのコード生成したものをファクトリメソッドから利用したら良いとは思う
- R.swiftは1つのファイルに全部の自動生成コードが入るのがデメリットではある
- そのコード生成したものをファクトリメソッドから利用したら良いとは思う
iOS x GraphQLの嬉しみとつらみ iOSDC2018
たぶんこんな内容だと思う
- GraphQLの特徴
- Facebook作のクエリ言語
- SQLライクに情報をリクエストすると複数の情報も一度のレスポンスにできる
- レスポンスの必須/非必須を表現できる
- エラーを返してくれる
- ページネーションの仕組みが考えられている
- Swiftのコードは型情報から自動生成できるライブラリがある(Apollo-iOS)
- GraphQLが最新のドキュメントになっている
- クライアントごとにAPIを作り分ける必要がない
- 短所
- N+1問題発生しやすい
- ステータスコードは基本200(ステータスコードでAPIの状態を表現しない)
感想
- Facebookは昔グラフAPIというのがRESET APIとは別に用意されていたのでそれに関係がありそう
- GitHubもGraphQLのAPIが用意されてる
- 何に役に立つかって言うと
- 1回のリクエストで済ませたいのに2,3回リクエストを送らないといけない場合があるでしょうと
- 例えばブログサービス作ってAPIを作った
- 1リクエストのAPIでユーザ情報を返すようにしたがフォロワー数はフォローAPIが必要
- 必要のない情報はレスポンスに含ませないこともできる
- Facebookと連携するアプリ作るときにGraphQL対応してるっていうのはでかい
- しかし自分たちが作ろうとするサービスがあったとしてGraphQL対応しようとすると大変だろうな
- 世の中サーバサイドでREST API実装したことがない人もまだままだ多い
- アプリ側がUXにあわせてRESET APIの設計を引っ張らないと結局あとで苦労するのはアプリ側
- GraphQLならリクエスト数を減らせることなどUXに柔軟に対応できるかもしれない
SSL証明証を検知する iOSDC2018
たぶんこんな内容だと思う
- HTTPSを使っても安全とは言い切れない
- MITM攻撃(マン・イン・ザ・ミドル アタック)される
- 悪意のあるFree WiFiとか
- 説明としてSSL通信の仕組みのための流れ
- クライアントがサーバに接続要求
- サーバがクライアントに公開鍵の送信
- 共通鍵の暗号化
- クライアントがサーバに暗号化したデータ送信
- MITM攻撃は
- クライアントとサーバの中間に立ちやりとりを仲介する中間者を立てることでクライアントのデータを見られる
- ピンどめ(SSL Pining)による解決法とは
- SSLサーバ証明書がクライアントが期待しているものと同一かを検証
- クライアントには事前に公開鍵が組み込まれているので比較できる
- ピン留めの種類
- 種類
- 証明書ピンどめ
- SSLサーバ証明書そのものが一致するか検証
- サーバ側で更新されるものなのでクライアントも更新する必要がある
- 公開鍵ピンどめ
- 証明書のもとになる公開鍵が一致するか検証
- 証明書ピンどめ
- どっちの種類を使うべき?
- Androidでは
- Android 7の公式
- 公開鍵のピンどめをサポート
- OkHttp
- 公開鍵のピンどめをサポート
- Android 7の公式
- iOSのライブラリやるなら
- APIKit
- 公式でできるわけではない
- SessionAdapterプロトコルに適合したクラスを実装すると
- 通信時のハンドラをカスタマイズできるのでそれ使う
- Alamofire
- 標準でサポートされている!!!
- Kyashはこれを使ってる
- APIKit
- Androidでは
- 種類
- SSLサーバ証明書の運用
- サーバの更新に合わせてクライアント側を強制で更新する
- サーバを先に更新すると困るのでクライアントは先に新旧両方の証明書を更新したものをアップデート
- よくある課題
- 強制アップデートも通信するならチェックされるから困るよね
- 別ホストかFirebaseでアップデートするかどうかをチェックする仕組み
- 強制アップデートも通信するならチェックされるから困るよね
- SSLサーバ証明書がクライアントが期待しているものと同一かを検証
- MITM攻撃(マン・イン・ザ・ミドル アタック)される
- 大事なこと
- アプリチームだけで判断せず相談しよう(別チームにセキュリティチームがいればそれが吉)
- 質問
- 公開鍵ピン留めのsha256のハッシュはハードコードとファイルどっちが良いの?
- どちらでも良い
- 公開鍵のハッシュはOpenSSLのコマンドで指定したドメインからとれるものなので
- 公開鍵ピン留めのsha256のハッシュはハードコードとファイルどっちが良いの?
感想
- MITM攻撃は簡単でCharlseなりmitmproxy使って端末にルート証明書入れれば通信は見られる
- Alamofireのこういうメリットが分かるのはいい
- Alamofire使ってもAPIKitライクな設計をするのは簡単なのでこういうときAlamofire使うのはいいと思う
- Youtubeでセキュリティに関する運用の話が見られるのは参考になります
SwiftConf '18 - Shai Mishali: RxSwift: debunking the myth of hard
たぶんこんな内容だと思う
- RxSwiftについての発表
- DisposeBagについて
- Subject
- PublishSubject, BehaviourSubject, ReplaySubjectの違いをうっすら
- それぞれをイラストでも示している
- Observableとの違い
- Control
- ControlEvent, ControlProperty, Binderについてを分類
- その他
- Driver
- CustomBinder
- Relay
- Signal
感想
- 初心者用ではないかもしれない
- Rxをやったことがある人なら分かる良さがある
- 類似のものを整理と比較していてとにかくわかりやすい
RxTest、RxBlockingによるテストパターン
たぶんこんな内容だと思う
- RxSwiftを使ったテストのパターンについて
- Quick/Nimbleも使ってる
感想
- RxTestとRxBlockingといいつつQuick/Nimbleも使ってる例になっていて、凄く良い
- 特にRxTestでexpectedの配列の展開がいい
- 自分は期待値を別の変数にして初期化したやつを使ってた
- 逆にQuick/Nimbleを使わない人にとっては読みづらいかもしれない
- 特にRxTestでexpectedの配列の展開がいい
Kotlin Fest 2018 Kotlin コルーチンを理解しよう
カンファレンス動画(アカウント登録が必要)
https://crash.academy/video/314/1617
発表資料
https://speakerdeck.com/sys1yagi/kotlin-korutinwo-li-jie-siyou
- コルーチンの歴史
- 55年前のコンウェイさんの論文
- COBOLのため
- 55年前のコンウェイさんの論文
- Kotlinのコルーチンでは
- Kotlinで書いたコードをJavaバイトコードにする際にコンパイラがコルーチン用のコードを自動で組み立ててステートマシンにしている
- コルーチンビルダー(引数にクロージャをとる関数)を使うことで実行スレッドを決定できる
感想
- Kotlinでは書いたコードをコンパイラがコルーチン用のコードに組み立てられる
- C#のコルーチンもJVMがバイトコードでコードを勝手にステートマシン化している
- Swiftもプログラマが書いたコルーチンAPI利用のコードを自動でステートマシン化してくれる
- Kotlinの方針はSwiftでも参考になるはず
- Kotlinのsuspend修飾子のやり方はSwiftでのasync/await的なやり方になるだろう
- Kotlinのasync/awaitもDeferred返すので同時実行できるけど、そのやり方はSwiftでのFuture利用となるだろう
- Swiftでもコルーチンビルダーがあればいいんだけどなあ
- スレッドの切り替えはコルーチン実行時にその中で切り替える必要がある
- KotlinのコルーチンはSwift利用者が欲しかったもののような気がする
- Futureを使わないSwiftのasync/awaitではsuspend修飾子を使ったもののようになることで、軽量なコルーチンをあれしている
あと、誰が言ったんだかわからないんですが、そもそもなんで大昔からあるコルーチンが最近流行ってんのかっていうのは次のツイートがなんとなく表している気がします
「そもそもシングルスレッドしか扱えない界隈もあってそっちではコルーチンが特に役立つ。それでコルーチンの良さが見直されてきた」というのも誰が言ってたんだか思い出せない
— y.imajo (@yimajo) 2018年12月23日
生きた仕様書としてのUIカタログアプリ運用 構想編
感想
- UIの仕様をカタログとして切り出すのは興味深いアプローチ
- Storybookっぽいとは思うもののアプリ開発者である私がやりたいのは画面仕様の確認なのでStorybookとは違うかもしれない
- 仕様をテストで担保するのはよくある
- テスターがいて手動でテストする工程があるならテスターが作るテスト仕様が実質仕様みたいなことに
- そうしないとテスターが何が正しいか判断できないからそうするしかない
- 結局これも確認の仕方は難しい
- テストコードが書かれていて自動化されている
- ロジックのテストはできるが見た目的な検証は難しい
- テスターがいて手動でテストする工程があるならテスターが作るテスト仕様が実質仕様みたいなことに
Kotlin と比較して理解する Swift 5 で実装されるかもしれない async/await について
こんな内容
- Kotlinのコルーチンはasync/awaitがありそれを使いやすくするsuspendがある
- suspendという概念はユニークなんだけどこれはSwift 5.xでもこんな感じになる
- なにそれ?
- SwiftもKotlinも非同期関数を同期的に記述して結果をラッピングせず取り出したい
- 言い換えるとアンラップした状態で取得したい
- なにそれ?
- Kotlinのasync/awaitは
Deferred<T>
ベース(Future/Promiseみたいなもの)- suspendはそれを取り出して取得できる
- しかしそうすると複数処理の待ち合わせみたいなことはできない
- そうしたら
Deferred<T>
使うじゃん
- suspendはそれを取り出して取得できる
- Swiftでも基本はsuspendのような感じで、Futureは自分で実装する
- suspendという概念はユニークなんだけどこれはSwift 5.xでもこんな感じになる
感想
- SwiftのほうはFutureの実装せずコルーチン導入後に議論などを後回しにできるためスモールスタートなんだろう
- Kotlinは一社で開発して一気に実装してexperimentalでリリースしてという勢いを感じる
- KotlinのコルーチンがRxとどんなふうに置き換わるかというのは参考になるはず
CodeZineにあるRxSwiftの記事(第4回)に対して自分ならこうするという話
こんな内容
- CodeZineのRxSwift記事に対してのツッコミ
- 「RxSwiftの仕組みを利用して、MVVMモデルを導入しよう - RxSwiftを使った一歩進んだiOSアプリ開発 第4回」
- CodeZineの記事は おそらく Rxの基礎を知らないまま書いている
- エラーハンドリングをしていない
- Rxのエラーはサブスクライブを停止させることを分かっていない
- UIのイベントをサブスクライブしているとUIが停止する
- 記事ではそれを回避するためかハンドリングせすrx.tap使ってる...
- UIのイベントをサブスクライブしているとUIが停止する
- Rxのエラーはサブスクライブを停止させることを分かっていない
- エラーハンドリングをしていない
- 自分がCodeZineの記事がいまいちだと思うのは
- Variableを使ってる(使えなくなるってわかってるものを使うのは技術的負債)
- サンプルコードで必要もないのにAlamofire使ってる
- 「protocolでテストが用意になります」と書いてあるのにテストコード書いていない
- 本当にテスト容易になる意味のあるprotocolなのかを示して欲しい
- サブスクライブでUIイベントを停止させられることを分かっていないから
- ViewControllerで.rx.tapから3文字以上の条件を書いてそこからObservableシーケンスをSubjectで発行している
感想
- そもそも正解なんてものはないけど
- アプリって長く運用保守していくこともあるので基礎が大事
- 長く運用する予定ないならそもそもRxSwift使わなきゃいい
- 技術記事を書いてるってことは経験があるんだろうけどそれでも基礎が足りてないように感じる
- RxSwiftは相当難しい
- 必要のないAlamofire使いたくなるんだろうけどそれを入門者に強いる前にURLSessionを知る必要がある
- (RxSwift入門者用には)自分のばりばりの手癖のあるコードを示すのではなく基礎が大事
- これ読んでほしい RxSwift研究読本1 入門編
- エラーハンドリングについて読んでほしくこれも書いた RxSwift研究読本2 エラーハンドリング編
おわりに
今年はGoogleからasync/awaitが使えるPromiseライブラリ https://github.com/google/promises がリリースされたんですが、使ってるという声を聞かず、記事も見かけません。それが少し残念というかもっと使われても良いのにと思います。このライブラリはもともとのasync/awaitが使えるPromiseライブラリ https://github.com/malcommac/Hydra を参考にしていて、コードベースもかなり似ています。まあスレッドでasync/awaitやろうとしたら方法は限られてくるからなのかもしれませんが、Google Promisesのインターフェースは比較的癖が少なく優等生感がバリバリで、そのパクられ元のHydraは優等生感よりもセンス重視なのがそれぞれの良いところでもあります。
2019年は新規でアプリを作るとして、もしSwiftに慣れていないならそのようなPromise系ライブラリを試したらいいのではないかと思います。他の言語や他プラットフォームでも使われる非同期処理手法であるPromiseでアプリを作っていくことはRxSwiftやReactiveSwiftを使うより断然楽ですし、Swift 5.xで導入される予定のコルーチンによるasync/awaitに先駆けてスレッドベースのasync/awaitを使えます。ちなみにスレッドでどのようにasync/awaitを実現しているかについては「async/await研究読本」 https://booth.pm/ja/items/898239 に書きました。
そもそもSwift 5.xでコルーチンが導入されてasync/awaitが使えるようになってもFuture(もしくはPromise)が導入されるわけではなさそうなため、Futureを自作していくかサードパーティのライブラリで導入することになるんですが、そのときそのFutureライブラリの良さを見極める必要性というのはでてくるわけです。そうなるとやっぱりあらかじめPromise系のライブラリ触ってるというのは必須ではないにしろ良い経験になるんじゃないかなーともおもいます。