iOSDC Japan 2016 参加メモ: A-8 デザイナーにStoryboardをお任せする技術
- はてな 加藤さん id:cockscomb
背景
今回のゴール
- デザイナーがStoryboardを編集するワークフローの獲得
- チームの生産性向上
導入
- チームや個人のモチベーション重視
- やる気がなさそうならさっさと諦める
- 開発環境をセットアップ
- 手取り足取り教える
- 実際に触れてもらう
Interface Builder
- 意外といろいろ新しい要素がある
デザイナ的には案外わかりやすい
登場する要素について
- View
- ここはわかりやすい
- ViewController
- 黄色いアイコンのやつがViewControllerだよ!
- Viewとペアになってるよ
- AutoLayout
- これが。。。。
- View
UIKit User Interface Catalog
- これを教えてあげるのが良い
- ViewController Catalog for iOS
- ちょっと古い
AutoLayout
教えるべきことがたくさんある
- Layout Constraint
- Intrisic Content Size
- Priority
- Error / Warning
NSLayoutConstraint
- 制約の式の中に対象のattributeなどを設定すると考える、というのを教えてあげる
- 揃える、という意識とConstraintは対応してるので意外と行ける
Intrinsic Size
- 固有のサイズって話でわかる
Priority
- 伸びにくさ、ちぢみにくさのPriorityのことを徐々に教えてあげる必要がある
- 絵で説明する
AutoLayoutのエラー
- エラーがあると怒られる
- どういう時に怒られるか知っておいてもらう
Adaptivity
- Dynamic Text
- Size Class
- Trait Collection
ここまで学ぶのにどこまで大変か?
ワークフロー
- アプリの機能が企画される
- デザイナーがレイアウトを決める
- エンジニアが実装
- デザイナが細部を調整
- コードレビュー
Make App Designable
- IBDesignable
- Storyboardで見れる
- IBInspectable
- Storyboardから値を設定できる
ヒント
- 前提を共有する
同じドメイン知識を共有する
- サービス
- プラットフォーム
- ユーザーインターフェース
用語をきっちり揃える
独自のViewをたくさん作る
- 再利用性のあるコンポーネント
- パラメータを @IBInspectable
- 最初から作り込み過ぎない
よく作る例
- Border
- 線の幅を指定できたり
- 物理pixcelにしたい場合、とか
- AttributedTLabel
- BorderedButton
- Border
エンジニアにとって大事なこと
- UIKitについて学ぶ
- 知らないことは意外と多い
- Storyboardを巧く管理する
- 分割は必須
- コンフリクトは最大の敵
- 同じ所を同時に触らない
- デザイン調整は後で、ぐらいでも良い
- デザイナーを手助けする
- 忙しい
- 丁寧なサポートを心がける
- レビューがあると安心感が出る
まとめ
- 開発チームが協力することで実現
- 難易度は高め
- 大きなメリット
- 同じ言葉で成果物をコミュニケーションできる
- デザイナーがトライアンドエラーしやすくなる
QA
Storyboardのレビューはどうしてる?
- 複雑な場合はcheckoutしてアウトラインで見てみたり
ContainerViewを多用したい場合はどうしている?
- エンジニア側でContainerを作ってStoryboardを分割してしまう
- 中身だけお願いします、みたいな
iOSDC Japan 2016 参加メモ: A-7 メモリー管理の嬉しいバイキング料理
- Ray Fix さん
- めっちゃ日本語うまい
メモリー管理
- ほぼ自動的にメモリ管理をしてくれる
- 仕組みがわかれば、バグの少ないアプリがかける
スタックとヒープ領域
スタック
- スタックはとにかく速い
- ロックする必要は全く無い
スタックから出るときには必ず開放が必要になる
もっと広く使いたい場合はヒープを使う
ヒープ領域
共通メモリ
- ヒープ領域に情報を確保し、スタックの領域の参照とカウントを持つ
参照型を使うときには、定数型をつかうと上書きのデメリットが消せる
循環参照問題
Swiftの弱い参照
Objective-Cの時は強い参照が0になると開放されていたが、Swiftではそうではない。
強い参照がなくなるとdeinitalizeが走って、weak countが0でない場合はゾンビができる
weak countが0になった時に、初めてメモリから開放される
- つまりweak 用のカウントは別にある
weak
- 参照先がゾンビの場合はnilを返すようになる
unowned
- 参照先がゾンビの場合はエラーになる
呼び出す場合の例
- Closureのなかで値を使う場合、selfをつけろと言われる
- 循環参照しているかもしれない!というヒントをXcodeがくれる
- キャプチャーリスト
[unowned self]
みたいにする
非同期の問題
- 非同期の場合、[unowned self] してしまうと、selfが消えてしまうことがある
- なので、書かないのが正解になる
また、そのような状況で循環参照を防ぐには
[weak self]
を使えばよいweak selfの場合、selfがOptionalになるので、実行されないところが出てくる
- それを防ぎたいなら storngSelfに代入するような
strong weak dance
のパターンでguardする
まとめ
しっかりメモリを理解してバグを少なく!
QAより
- Apple的には、あんまりキャプチャするのは良いと思ってない様子
- back tick selfを使ってる人もいるが、MLでバグだ、っていう話になってたので、strong weak selfの方がいいはず
iOSDC Japan 2016 参加メモ: A-6 ドッグフーディングしやすい環境を整える
- 西さん Yahoo!Japan
ドッグフーディング
- 自分で使い倒す
- 継続するのは色々大変
きっかけ
数千人の全社員に配布してフィードバックをもらおう!
- 結果はアンケートフォームに!
- 結果が10件...
きっとやり方が悪い
改善ポイントを探す
- アプリ利用依頼
- DL
- フィードバック作成
- プライバシー
アプリ利用依頼
- 新機能つけました、やってみてください -> ダメ
- メリットがわからない
- テストアプリのメリットを分かる形で伝えるようにする
アプリDL
- Apple Developer Enterprise Programに参加して配布
AppStoreから入れたアプリを消したくはない
- bundle Identiierを変更すれば削除せずに済む
普段使いの環境を壊さない
フィードバック作成
- 鬼門
- 悪いところを見つけても、文章もキャプチャも色々面倒
- フィードバックを楽にする仕組みをできるだけ楽に
テスト配布版にだけ現れるレポート用画面を用意
運用でカバーせず、社員も一般ユーザーとみなしてあげる
プライバシー配慮
- そのままスクショを送るとIDばれちゃう!
- フィードバックの手が止まる
- キャプチャ時にその辺をマスクするような処理
改善後
- 10件 -> 1600件!!
その後の変化
チームのモチベーション向上
- 人に見られると議論が活発になる
良くないものを良くないと言いやすくなった
おまけ
- FeedbackKit 公開
- 機能
- メール送信・カスタムでSlack送信
まとめ
- ドッグフーディングを継続していきましょう
iOSDC Japan 2016 参加メモ: A-5 Reactive State Machine
- @inamiy さん LINE
リアクティブプログラミング
時間経過に伴うイベントストリーム
FRP 関数型リアクティブプログラミング
- データフローを構築する
データフロー = 川の流れ
- 流れてくる状態の管理
Data Binding
- 定期的にデータを流して、データを常に変更できる状態に
Data Observing
- KVO出ないかぎり、永続監視はできない
- 継続的なデータフローとして永続化したい
Observable / Signal = EventEmitter
Variable / Mutable Property = EventEmitterの現在の値
FRP + MVVM で簡単になる
- 本当に?
ポケモンに例えてみるw
ViewModelがどんどんできてくる
- Viewの数だけViewModelが出来上がってしまう
これらが相互に連携して・・・複雑なデータフローを形成していってしまう
- つらい
FRP + MVVM
- フロー構築は楽になる
- 状態管理が楽になるわけではない
FRP + MVVMの問題点
- let Variableとvar rawValueと変わらない
データフローそのものが状態になってしまう
状態操作は楽になった
- が、状態の数は増えてしまった
どうすればいいのか
発送の転換
- データフローの固定化
- 状態の数を最小化
React.js
React.jsとは
Viewをステートレスに扱うフレームワーク
- 狭義の意味でのリアクティブプログラミングってわけじゃないよ
親の一つだけがstateful
子が全てstateless
しかし、データフロー構築は面倒
- 子から親へのデータフローが辛い
Redux
- 状態を一つのコンテナで管理
- 状態の管理がシングルトンにまとまる
問題点もある
Middlewareの位置づけ
- 役割が明確に位置づけられているが、分割しすぎていて面倒になる
- Reducerと密結合な方が楽なこともある
非同期処理が難しい
- 同期処理を前提に設計されているので、非同期に連鎖反応した時にフローが予測しにくい
- 非同期処理はFRPに任せてしまったほうがシンプル
Reduxの型を眺める
- よく見ると、State Machineのことを言っている
- ミーリ・マシンと同じ
Redux + FRP
- ReducerとMiddlewareを統合
- Reducerの返り値をOptionalに
- 状態遷移の失敗のケア
非同期処理にFRPをつかう
ReactiveAutomaton / RxAutomaton
- というのを作った
- https://gist.github.com/inamiy/1835a88e00bd19dff003e779fe63a2ed
- サンプルの紹介
ReactiveAutomatonまとめ
*小さな状態管理から大きなシングルトンまで幅広く対応可能 * Elmの基本設計に近い
Model View ViewModel -> Model View Automatonへ
まとめ
iOSDC Japan 2016 参加メモ: A-3 iOS 10時代の新しいCollectionView使いこなし術
- @TachibanaKaoru さん
New Lifecycle of Cell
- iOS 10からcellのライフライクルが変わる
現在のライフライクルの復讐
- cellForItemAtIndexPath によって画面内の分生成され、それが画面外に出ると次のcellに使いまわされる
- 1画面分のcellが作られていた
- 元々、このスタイルはTableViewで考えられたスタイルだが、CollectionViewでは一気に複数使いまわされることもあった
iOS 10から
- 画面外に用意されるcellの数がぐっと多くなった
- 1.5画面分用意されるようになった
- willDisplayCellとcellForItemAtIndexPathの時間差が大きくなった
prefetch API
- ライフサイクルで増えた分より、更に奥のセルに対してprefetchすることができるようになった
- prefetchのキャンセルも出る
- かなり事前に作れるので、ユーザー体験が上がる
iOS9以前では、どうすると軽くできる?
基本だが
- CollectionViewよりTableView
重い処理はcellForItemAtIndexPathでやろう
willDisplayCell / didEndDisplayCell は軽めに
描画処理の高速化
- Blend-Layer処理をなるべく使わない
- シミュレータの Color Blend Layerをチェック入れるとわかる
- 赤がBlend 緑がBlendじゃない
- 緑を増やそう
- 透過pngやclearColor背景を使わない
- 画像に背景色を含めてしまったりするといい
- 角丸やシャドウを画像に含めてもらうほうが高速
- Blend-Layer処理をなるべく使わない
QA
prefetchはデリゲート?iOS9の時に書いてあっても大丈夫?
- iOS9だと呼ばれないだけだから大丈夫!
prefetchはどういう処理に向いてる?
- 画像の先読みや、計算が必要な処理にいいかも
- cell自体はまだ存在しない段階
iOSDC Japan 2016 参加メモ: A-2 RxSwiftは開発をどう変えたか
- ishkawaさん
RxSwift
イベントストリームを抽象化
- UIの変化やアクションなど
Observable
- イベントストリームを表す型
subscribe(_:)
- イベントごとにクロージャを実行
- イベントを受け取って実行できる
bindTo(_:)
- Observer
に自動反映する - イベントストリームに接続できる
- Observer
Observable と Observerは対になる概念
- 入出力の関係
Operator
- 実際の開発では、streamの間にOperatorを挟んで色々変換をしてデータを加工したりしていく
- map, filterなど
もう少しアプリらしい例
- 苗字と名前を入れてsubmitすると、くっついたフルネームがUILabelに反映される
- combineLatestとsample
- 複数のobservableを組み合わせ、sampleでタイミングを調整
Rx vs 従来のイメージ
Rx
- 水道のイメージ
- 蛇口と、それをバルブなどで調整してる
- 水道のイメージ
従来
- バケツのイメージ
- バケツにデータを貯めといて、それを取りに行く
- バケツのイメージ
Rxの概念とは
- 全てのイベントストリームの表現手段が同じ
- ためておいて後で取りに行く、という動作がない
- イベントストリームの依存関係がoperatorで表される
現在地の天気アプリの例
- 位置情報を許可すると、天気が出る
位置情報を拒否すると、NGと出る
コード紹介
- 従来のスタイルでデリゲートスタイルで書くと、パッと全体のフローを把握するのが難しい
- Rxのコードだと、処理の流れに沿ってコードが追える
- ここで何が起きてるのか、というのがそこを見ればわかる
複雑な制御がイベントストリームだけでかける
- 処理の依存関係が見えるようになった
まとめ
- イベントストリームを宣言的に扱えるようになった
- 複雑なイベントストリームでも全体を把握しやすい
- データを貯めなくて良くなり、ストアドプロパティを減らせる
iOSDC Japan 2016 参加メモ: A-1 - Handling rich text in Swift
- Realm 岸川さん
何も考えずにiOSのテキストを作ると、色々ずれてたり、切れてたりしてしまう。
デザイナさんはここを直してほしい、というけどiOSのラベルでは難しい、とか、そういう状況をなくしていくためにTextを理解しよう。
アジェンダ
TextKit
- iOS7から導入
- CoreTextをベースに作られている
- UIKItとの統合
- UILabel / UITextView などのベース
UILabel
- ヒラギノとシステムフォント
system font
- 英字はsanfrancisco
- 日本語はヒラギノにフォールバック
明示的にヒラギノを指定したりすると、英字もヒラギノになり、ベースラインより下にはみ出るものが切れてしまったりする
- 日本語ははみ出る文字がないので無事だが。。。
中身のテキストによって切れてしまう。
なぜこんなことが起こるのか?
行の高さを知る
- アルファベットのFontのお話
- BaselineやCap height、Ascent、Descent、x-heightなど
- これらのFont metricsによって高さが決まる
systemfontは、これらが全体にだいたい収まるようになっている
ヒラギノは特殊なメトリクスを持つ
- Ascent Descentが狭い(半分ずつ)
- Noto Sans CJK なんかだと大丈夫だたりする
-
- 上下にDescentを補う
- Descentを倍にする
- 上下にDescentを補う
いったんまとめ
ヒラギノのメトリクスに注意
Tips 日本語フォントにフォールバックを指定することはできる
Tips
- 描画サイズを得る
- iOS7からならできる
UITextView
普通につかう
- ヒラギノを指定すると、だいぶ大きくなったりする
TextViewにはデフォルトのマージンがある
- textContainerInset
- lineFragmentPadding
- ヒラギノの場合は font.leadingという値のぶん高さがついてくる
デフォルトのスタイルをリセットする
textView.textContainerInset = UIEdgeInsetsZero textView.textContainer.lineFragmentPadding = 0 textView.layoutManager.usesFontLeading = false // leadingを取り除く
- ドキュメントには、UIに使うときはleadingはoffにすると良いよって書いてある
- leadingを含めた描画サイズをオプションを指定することで取ることもできる
これを元に様々なスタイルに対応する
行間の変更
- NSAttributedString
- NSParagraphStyle
- minimumLineHeight
- maximumLineHeight
- これを同一にすると行の高さが一致する
- これらは、複数のフォントサイズが混在する文章のためにある
- lineSpacing = 8
NSAttributedStringを活用する