iOS
essay
iOSDay 25

2018年のiOSアプリ開発記事を振り返る

はじめに

2018年のiOSアプリ開発の振り返りとして技術記事/動画を勝手に振り返ってみます。
ランキングではなく個人的に何回か読み返した記事となります。
ですのでここにはない分かりやすく有用なTipsなんかも今年多くあったとは思うのですが、それらについては記載してません。

紹介する記事/動画については私の理解でその概要と感想を書いていますが、間違えているかもしれませんね。みなさんもし間違っていたら教えていただけるとありがたいです。

Swift.Decodable + Int64 / iOS 10 = 要注意

https://techlife.cookpad.com/entry/2018/03/06/100121

たぶんこんな事が書いてある

  • 概要
    • サーバサイドのレスポンスを内部のインスタンス化する際にエラーになった
    • 新規(もしくはHimotokiからの移行?)でSwift.Decodableを使ってた
    • Int64とiOS10のデバイスでのみ再現する
  • 経緯
    • 1000000000000000070をInt64のidにDecodeするとiOS10デバイスでエラーする再現ができた
    • SwiftはオープンソースなのでInt64のデコードでエラーがでる部分を調べた
      • そのコードだけでは判定がエラーになることしかわからない
      • iOS11ではNSNumberを使うところがiOS10ではNSDecimalNumberを使っているのが原因と予測
  • 回避策
    • 結果的に値が大きいときはHimotokiを使うことにした

感想

  • 1000000000000000071でエラーにならないとも書いている部分がイマイチよくわからない
    • 1000000000000000070では問題ありエラー
    • 1000000000000000071では問題ないらしい(なぜ値が大きくなったのに?)
    • 1000000000000000080でも問題ありエラー
  • そもそもこれとは別の話だけど関連性のある話題として
    • アプリではユースケースとしてidなどが64bit超えの値を使いたいというのがある
      • サーバサイドでidをAuto Incrementしているのだろう
      • ユーザ参加型のコンテンツは数がめちゃくちゃ増えるので64bit整数が使われる
    • しかしアプリとしたらidはStringでサーバサイドから返ってくればいい
      • レスポンスとして idはStringで返したらいいんじゃない? といつも思う
        • Int64だとか考えなくて良くなるし

Storyboardとの付き合い方 2018

https://blog.ishkawa.org/2018/08/13/1534116670/

たぶんこんな事が書いてある

  • IBDesignableのテクニックとしてモジュール分割する
    • IBDesignableのプレビューのためにそのターゲットのクラスたちがビルドされ時間かかる
      • モジュール分割しておけばビルド対象のコードを減らせる
  • スタイルの指定はクラスが行いIB上で繰り返さない
    • IB上で指定しない
    • IBの「User Defined Runtime Attributes」も使わない
  • 画面遷移でsegueを使わずにファクトリメソッドで遷移する
    • segueの値はコードでも管理しないと二重管理になってしまうから

感想

  • スタイル の指定をIBでやらないのは経験上有りだと思う
    • 「User Defined Runtime Attributes」の文字列での指定はマジしんどいし
      • やっぱりパラメータ指定はコンパイルエラー出してほしい
    • 「User Defined Runtime Attributes」で頑張って指定できるようにしがち
      • 文字列指定からスタイリングの振る舞いを決定するようなコードにしがち
        • コピペミスしても気づけずコンパイルエラーにならないので困りがち
  • segueの二重管理の件はR.swiftなりSwiftGen使えばStoryboardファイルからコードを生成できる
    • そのコード生成したものをファクトリメソッドから利用したら良いとは思う
    • R.swiftは1つのファイルに全部の自動生成コードが入るのがデメリットではある

iOS x GraphQLの嬉しみとつらみ iOSDC2018

https://www.youtube.com/watch?v=g9ZMJrc4fjc

たぶんこんな内容だと思う

  • 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://www.youtube.com/watch?v=DjKsy5jBM2w

たぶんこんな内容だと思う

  • HTTPSを使っても安全とは言い切れない
    • MITM攻撃(マン・イン・ザ・ミドル アタック)される
      • 悪意のあるFree WiFiとか
    • 説明としてSSL通信の仕組みのための流れ
      • クライアントがサーバに接続要求
      • サーバがクライアントに公開鍵の送信
      • 共通鍵の暗号化
      • クライアントがサーバに暗号化したデータ送信
    • MITM攻撃は
      • クライアントとサーバの中間に立ちやりとりを仲介する中間者を立てることでクライアントのデータを見られる
    • ピンどめ(SSL Pining)による解決法とは
      • SSLサーバ証明書がクライアントが期待しているものと同一かを検証
        • クライアントには事前に公開鍵が組み込まれているので比較できる
      • ピン留めの種類
        • 種類
          • 証明書ピンどめ
            • SSLサーバ証明書そのものが一致するか検証
            • サーバ側で更新されるものなのでクライアントも更新する必要がある
          • 公開鍵ピンどめ
            • 証明書のもとになる公開鍵が一致するか検証
        • どっちの種類を使うべき?
          • Androidでは
            • Android 7の公式
              • 公開鍵のピンどめをサポート
            • OkHttp
              • 公開鍵のピンどめをサポート
          • iOSのライブラリやるなら
            • APIKit
              • 公式でできるわけではない
              • SessionAdapterプロトコルに適合したクラスを実装すると
                • 通信時のハンドラをカスタマイズできるのでそれ使う
            • Alamofire
              • 標準でサポートされている!!!
              • Kyashはこれを使ってる
      • SSLサーバ証明書の運用
        • サーバの更新に合わせてクライアント側を強制で更新する
        • サーバを先に更新すると困るのでクライアントは先に新旧両方の証明書を更新したものをアップデート
      • よくある課題
        • 強制アップデートも通信するならチェックされるから困るよね
          • 別ホストかFirebaseでアップデートするかどうかをチェックする仕組み
  • 大事なこと
    • アプリチームだけで判断せず相談しよう(別チームにセキュリティチームがいればそれが吉)
  • 質問
    • 公開鍵ピン留めのsha256のハッシュはハードコードとファイルどっちが良いの?
      • どちらでも良い
      • 公開鍵のハッシュはOpenSSLのコマンドで指定したドメインからとれるものなので

感想

  • MITM攻撃は簡単でCharlseなりmitmproxy使って端末にルート証明書入れれば通信は見られる
  • Alamofireのこういうメリットが分かるのはいい
    • Alamofire使ってもAPIKitライクな設計をするのは簡単なのでこういうときAlamofire使うのはいいと思う
  • Youtubeでセキュリティに関する運用の話が見られるのは参考になります

SwiftConf '18 - Shai Mishali: RxSwift: debunking the myth of hard

https://www.youtube.com/watch?v=GdvLP0ZAhhc

たぶんこんな内容だと思う

  • RxSwiftについての発表
    • DisposeBagについて
    • Subject
      • PublishSubject, BehaviourSubject, ReplaySubjectの違いをうっすら
      • それぞれをイラストでも示している
      • Observableとの違い
    • Control
      • ControlEvent, ControlProperty, Binderについてを分類
    • その他
      • Driver
      • CustomBinder
      • Relay
      • Signal

感想

  • 初心者用ではないかもしれない
    • Rxをやったことがある人なら分かる良さがある
    • 類似のものを整理と比較していてとにかくわかりやすい

RxTest、RxBlockingによるテストパターン

https://qiita.com/takehilo/items/09f4a3077e441e5bb9de

たぶんこんな内容だと思う

  • RxSwiftを使ったテストのパターンについて
    • Quick/Nimbleも使ってる

感想

  • RxTestとRxBlockingといいつつQuick/Nimbleも使ってる例になっていて、凄く良い
    • 特にRxTestでexpectedの配列の展開がいい
      • 自分は期待値を別の変数にして初期化したやつを使ってた
    • 逆にQuick/Nimbleを使わない人にとっては読みづらいかもしれない
  • 私だったらbeforeEachで変数のセットアップする
    • 例えばlet xs1 = scheduler.createHotObservable(...)のような入力のObservable
    • こうしてしまうと
      • beforeEachの前に宣言してbeforeEachで代入になり別になってしまうけど
        • beforeEachで結果が変わる条件が揃っていることで他の人のテストコードも読みやすくなるほうがメリット多い気がする
      • beforeEachの値と、itでの値の比較記述が遠くなる気がするけど
        • contextが共通しているので問題ないと考える

Kotlin Fest 2018 Kotlin コルーチンを理解しよう

カンファレンス動画(アカウント登録が必要)
https://crash.academy/video/314/1617

発表資料
https://speakerdeck.com/sys1yagi/kotlin-korutinwo-li-jie-siyou

  • コルーチンの歴史
    • 55年前のコンウェイさんの論文
      • COBOLのため
  • Kotlinのコルーチンでは
    • Kotlinで書いたコードをJavaバイトコードにする際にコンパイラがコルーチン用のコードを自動で組み立ててステートマシンにしている
  • コルーチンビルダー(引数にクロージャをとる関数)を使うことで実行スレッドを決定できる

感想

  • Kotlinでは書いたコードをコンパイラがコルーチン用のコードに組み立てられる
    • C#のコルーチンもJVMがバイトコードでコードを勝手にステートマシン化している
  • Swiftもプログラマが書いたコルーチンAPI利用のコードを自動でステートマシン化してくれる
    • Kotlinの方針はSwiftでも参考になるはず
    • Kotlinのsuspend修飾子のやり方はSwiftでのasync/await的なやり方になるだろう
    • Kotlinのasync/awaitもDefferd返すので同時実行できるけど、そのやり方はSwiftでのFuture利用となるだろう
  • Swiftでもコルーチンビルダーがあればいいんだけどなあ
    • スレッドの切り替えはコルーチン実行時にその中で切り替える必要がある
  • KotlinのコルーチンはSwift利用者が欲しかったもののような気がする
    • Futureを使わないSwiftのasync/awaitではsuspend修飾子を使ったもののようになることで、軽量なコルーチンをあれしている

あと、誰が言ったんだかわからないんですが、そもそもなんで大昔からあるコルーチンが最近流行ってんのかっていうのは次のツイートがなんとなく表している気がします

生きた仕様書としてのUIカタログアプリ運用 構想編

https://speakerdeck.com/hiragram/sheng-kitashi-yang-shu-tositefalseuikataroguapuriyun-yong-gou-xiang-bian

感想

  • UIの仕様をカタログとして切り出すのは興味深いアプローチ
    • Storybookっぽいとは思うもののアプリ開発者である私がやりたいのは画面仕様の確認なのでStorybookとは違うかもしれない
  • 仕様をテストで担保するのはよくある
    • テスターがいて手動でテストする工程があるならテスターが作るテスト仕様が実質仕様みたいなことに
      • そうしないとテスターが何が正しいか判断できないからそうするしかない
      • 結局これも確認の仕方は難しい
    • テストコードが書かれていて自動化されている
      • ロジックのテストはできるが見た目的な検証は難しい

Kotlin と比較して理解する Swift 5 で実装されるかもしれない async/await について

https://speakerdeck.com/yimajo/await-nituite

こんな内容

  • Kotlinのコルーチンはasync/awaitがありそれを使いやすくするsuspendがある
    • suspendという概念はユニークなんだけどこれはSwift 5.xでもこんな感じになる
      • なにそれ?
        • SwiftもKotlinも非同期関数を同期的に記述して結果をラッピングせず取り出したい
        • 言い換えるとアンラップした状態で取得したい
    • Kotlinのasync/awaitはDeffered<T>ベース(Future/Promiseみたいなもの)
      • suspendはそれを取り出して取得できる
        • しかしそうすると複数処理の待ち合わせみたいなことはできない
        • そうしたらDeffered<T>使うじゃん
    • Swiftでも基本はsuspendのような感じで、Futureは自分で実装する

感想

  • SwiftのほうはFutureの実装せずコルーチン導入後に議論などを後回しにできるためスモールスタートなんだろう
    • Kotlinは一社で開発して一気に実装してexperimentalでリリースしてという勢いを感じる
  • KotlinのコルーチンがRxとどんなふうに置き換わるかというのは参考になるはず

CodeZineにあるRxSwiftの記事(第4回)に対して自分ならこうするという話

https://qiita.com/yimajo/items/947e1a8fc15f577779af

こんな内容

  • CodeZineのRxSwift記事に対してのツッコミ
    • 「RxSwiftの仕組みを利用して、MVVMモデルを導入しよう - RxSwiftを使った一歩進んだiOSアプリ開発 第4回」
    • CodeZineの記事は おそらく Rxの基礎を知らないまま書いている
      • エラーハンドリングをしていない
        • Rxのエラーはサブスクライブを停止させることを分かっていない
          • UIのイベントをサブスクライブしているとUIが停止する
            • 記事ではそれを回避するためかハンドリングせすrx.tap使ってる...
    • 自分がCodeZineの記事がいまいちだと思うのは
      • Variableを使ってる(使えなくなるってわかってるものを使うのは技術的負債)
      • サンプルコードで必要もないのにAlamofire使ってる
      • 「protocolでテストが用意になります」と書いてあるのにテストコード書いていない
        • 本当にテスト容易になる意味のあるprotocolなのかを示して欲しい
      • サブスクライブでUIイベントを停止させられることを分かっていないから
        • ViewControllerで.rx.tapから3文字以上の条件を書いてそこからObservableシーケンスをSubjectで発行している

感想

  • そもそも正解なんてものはないけど
    • アプリって長く運用保守していくこともあるので基礎が大事
    • 長く運用する予定ないならそもそもRxSwift使わなきゃいい
  • 技術記事を書いてるってことは経験があるんだろうけどそれでも基礎が足りてないように感じる
    • RxSwiftは相当難しい
  • 必要のないAlamofire使いたくなるんだろうけどそれを入門者に強いる前にURLSessionを知る必要がある
  • (RxSwift入門者用には)自分のばりばりの手癖のあるコードを示すのではなく基礎が大事

おわりに

今年は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系のライブラリ触ってるというのは必須ではないにしろ良い経験になるんじゃないかなーともおもいます。