読者です 読者をやめる 読者になる 読者になる

UIをSwiftyに書く | try! Swift Tokyo 2017 #tryswiftconf Day1-10 聞き起こし

try! Swift Tokyo 2017

twitter.com

この講演では、Swiftの構造と特性がアプリとUIのコードをより完結に書けるようにしているかということを探っていきます。 私たちは、UIレイヤーを構築する際の一般的な落とし穴と課題を見ていき、それを改善するためのSwiftyな方法を検討します。 Enumを用いたビューの状態のモデリング、有用なサードパーティ製のSwiftライブラリ、プロトコルによるビューの統一などを見ていきます。

UIをSwiftyに書く

f:id:niwatako:20170302154205j:plain

小さな会社なのでアプリを1から作ります。

Swiftで

f:id:niwatako:20170302154242j:plain

ワクワクしました。

f:id:niwatako:20170302154300j:plain

書いているとパターンが見えてきました。パターンがUI関連であることもよく有ります。

f:id:niwatako:20170302154325j:plain

今日は4つのパターンを紹介します。

デモをお見せします

f:id:niwatako:20170302154345j:plain

スターウォーズAPIを使います。

f:id:niwatako:20170302154425j:plain

f:id:niwatako:20170302154427j:plain

シンプルなアプリケーションですがポイントの説明にはこれで十分でしょう。

シュレディンガーの結果

f:id:niwatako:20170302154505j:plain

データを取得して返ってくる。失敗したらエラーとともに帰ってくる。

f:id:niwatako:20170302154525j:plain

成功化失敗、どちらかが大抵です。

f:id:niwatako:20170302154545j:plain

でもありうるな結果はたくさんあります。

f:id:niwatako:20170302154448j:plain

ハンドリングするべきは成功失敗の2つ。そこでモデリング化します。

f:id:niwatako:20170302154608j:plain

Result

完璧なSwiftのEnumユースケースです。

成功したら非オプショナルの型T、失敗したら非オプショナルの型Errorが帰ってきます

f:id:niwatako:20170302154722j:plain

f:id:niwatako:20170302154806j:plain

ViewControllerがシンプルになりました。

f:id:niwatako:20170302154819j:plain

f:id:niwatako:20170302154826j:plain

取得した結果を表示することも有りますね。

お気に入りのSwiftらしいやり方でAutoLayoutのお話をします。

f:id:niwatako:20170302154857j:plain

layoutSubviews() でレイアウトをするという方法がありますね

でもサイズごとに対応するとほぼ不可能になってしまいますね。

f:id:niwatako:20170302154925j:plain

プロダクションコードではStoryboardを使うべきではないという前提でお話をします

マージコンフリクトもあると大変です。アプリの中でUIの中でカラーやフォントを何度も反復することもあります。本来は分解すべきです。色を参照する時に16進数になってしまいます。

プロダクションでStoryboardを使うと文字別で識別されているので強い型付けが台無しです。

どうしてもStoryboardを使う場合にはコード生成ツールが助けになります。

最後にStoryboardに関して、Outletを接続することがコンパイルでは矯正されていません。

つなげてから名前を変更すると実行時にクラッシュします。

Autolayout

f:id:niwatako:20170302155142j:plain

f:id:niwatako:20170302155201j:plain

CartographyはAutolayoutの制約条件を見事に定義できます。オペレーターのオーバーロードを活用しています。

f:id:niwatako:20170302155252j:plain

方程式を書いている。

状態

f:id:niwatako:20170302155349j:plain

f:id:niwatako:20170302155402j:plain

f:id:niwatako:20170302155412j:plain

ロード中か、成功したか、失敗したか

f:id:niwatako:20170302155440j:plain

どう管理したら良いでしょうか

f:id:niwatako:20170302155447j:plain

ViewControllerでisLoading, isErrorなどのフラグを用意します

f:id:niwatako:20170302155509j:plain

素晴らしくはありませんね。

f:id:niwatako:20170302155528j:plain

実際に存在する以上の状態を表現しています。APIの結果でも同じことが有りました。

f:id:niwatako:20170302155558j:plain

データとフラグを独立して設定することもできます。

フラグが設定されていない場合にのみデータが存在するべきです。

あたいを関連付けしたEnumに似ていますね

ローディング中は何もない、読み込んだらデータが有る、失敗したらエラーが有る

f:id:niwatako:20170302155635j:plain

このようなEnumを用意し、欲しい状態でViewを初期化出来る。

ViewはSwitchステートメントで必要な状態に変更します。

Viewの他の箇所では表示非表示を変えることができます。

ViewControllerのコードも簡素になります。

f:id:niwatako:20170302155737j:plain

あたいを関連付けしたEnumで状態を表すことでViewのロジックを一元化できます。

Viewの状態管理をもっと簡略化出来るでしょう。

2つ目のViewControllerは3つの同じView状態を取るようです

f:id:niwatako:20170302155822j:plain

APIを叩き、ロードし、データを表示する。

f:id:niwatako:20170302155836j:plain

いつも3つの状態を辿っているのであればそれぞれのViewを基本的な実装を決めて表示非表示を一括で実装できたら便利ではないでしょうか

f:id:niwatako:20170302155917j:plain

プロトコルを利用すると良いでしょう。

プロトコルは何を用意する必要があるでしょうか

f:id:niwatako:20170302155950j:plain

f:id:niwatako:20170302160022j:plain

f:id:niwatako:20170302160034j:plain

update関数のデフォルト実装を作ることが出来るようになります。

f:id:niwatako:20170302160127j:plain

エラービューを提供し、ローディングビューを提供し、データをセットできるようにして、適切なタイミングでupdate()をコールすれば良い。

f:id:niwatako:20170302160156j:plain

f:id:niwatako:20170302160212j:plain

この物語の教訓は何でしょうか

プロトコルにすることでコードの反復を減らせます

f:id:niwatako:20170302160234j:plain

  • データとエラーの操作の仕方を簡単に区別できるようになります
  • Autolayoutの可読性にCartgraphyを紹介しました
  • ViewStateのバグを回避できるEnumを用意しました
  • プロトコル指向のプログラミングによりコードの重複を回避しました

f:id:niwatako:20170302160323j:plain

Q&A

あなたの考えでは、Enum以外の方法はお使いになったことは有りますか?GenericなViewControllerを作成したり、Enumを使って関連付けられた値を使っていますか?

ほとんど一般化されたEnumを使っています。GenericなViewControllerも利用しています。 ピークパターン、アクションパターンなどを分解してオブジェクトにしてぽぴゅれーとする方法とか、他の方法も検討しています。Enumはお気に入りで一般的な反復されるコードを簡略化出来るのでパターンとして利用しています。