「iOSオールスターズ勉強会」に参加してきました #dotsios

  • 88
    いいね
  • 2
    コメント
この記事は最終更新日から1年以上が経過しています。

cover.png

iOSオールスターズ勉強会

東京都内で iOS 勉強会が開催されるとのことで、傍聴しに行って参りました。とてもためになる発表ばかりだったので参加して良かったです。

今回会場で書いたメモ書きをこちらにまとめておきます。もし内容に問題があればご指摘ください。
私の Swift 力が足りないもので理解に偏りがあるのはご了承ください。

会場

日時:2015.02.14 (土) 13:30 〜 18:30
会場:デジタルガレージ様/Open Network Lab様
ハッシュタグ:#dotsios

きれいな会場でした。
また、受付のお姉さん方がすごくテンションが高く印象的でした。

関連記事

dots. イベント概要
http://eventdots.jp/event/311301

dots. イベントレポート
http://eventdots.jp/event/311301#repo

togetter まとめ
http://togetter.com/li/782943

[イベントレポート] iOS オールスターズ勉強会 #dotsios
http://dev.classmethod.jp/smartphone/ios-all-stars-report/

『Adaptive Collection View』

 LINE株式会社 石川洋資氏

資料

https://speakerdeck.com/ishkawa/adaptive-collection-view
https://github.com/ishkawa/sandbox/tree/master/Adaptive

Adaptivity

WWDC2014で話題になった "Adaptivity"

iOS 8 では Auto Layout や Size Classes によって View Controller が進化したよ。デバイスごとにサイズの異なる UI をこれまでよりも簡単に作りやすくなったよ。

iPhone & iPad でよくある画面構成

同じデータをそれぞれ違う形式、iPhone ではリスト形式、iPad ではグリッド形式で表示したい場合。

iPhone iPad
VC UITableViewController UICollectionViewController
View UITableView UICollectionView
Cell UITableViewCell UICollectionViewCell
DataSource UITableViewDataSource UICollectionViewDataSource
Delegate UITableViewDelegate UICollectionViewDelegate

このように同じようなコードを大量に2回書く必要があって大変。ならば、

UITableView の代わりに UICollectionView で実装してしまおう。

レイアウト

レイアウトは UICollectionViewLayout のサブクラスを作って、iPhone, iPad モードをそれぞれ用意。

  • iPhone: Table レイアウト
  • iPad: Flow レイアウト

セル

UITableViewCell 風にするには、セルを UICollectionViewCell 、セパレータを Decoration View で実装する。

モードに応じた estimatedItemSize を設定しておくと Self Sizing Cell が使える。

iOS 7 でも Self Sizing Cell を真似する

iOS 7 のシェアはまだ25%もある。(15.02.14現在)
Self Sizing Cell は iOS 8 からの機能。iOS 7 でもこれを真似したいがどうすればよいか?

-itemSizeForIndexPath:-systemLayoutSizeFittingSize: を呼びだす。

注意点

  • iPad だと Split View だったり Pop Over の場面も考え得るので、~ipad を使うよりも Size Classes で対応してあげたほうが良い
  • -systemLayoutSizeFittingSize: は重い、という指摘も
  • UITableView にしかない機能(reorderなど)は独自に実装する必要がある
  • UICollectionView の罠に気をつけよう
  • WWDC2014 "Advanced User Interfaces with Collection Views" で並べ替えやスワイプ削除の解説がある模様

まとめ

  • Adaptivity の進化によって、デバイスの違いをそれほど意識せずとも対応しやすくなった (iOS 8)
  • UICollectionView で UITableView を置き換えて更に Adaptive に
  • そうすることでデバイスの区別をしなくてもよくなる
  • よってひとつのコードですべてに対応できる

iPhone だけに対応したつもりが iPad にも反映されていて結果的に評判が良かった。

という話が印象的でした。同じコードを2度書く必要がないというのは理想的ですし、これは良いパターンな気がします。ただ UICollectionView は UITableView を完全に置き換えるものではないので、よく注意して実装する必要がありそうです。

『Swiftで使いやすいAPIを考える』

 株式会社ユビレジ 岸川克己氏

KeychainAccess ライブラリを実装した際の知見など。

資料

https://speakerdeck.com/kishikawakatsumi/swiftderaiburariwoshu-kuji-falsepurakuteisu

KeychainAccess
https://github.com/kishikawakatsumi/KeychainAccess

  • メソッドチェーン
  • iCloud 対応
  • Touch ID 対応

ObjC との違い

  • データ型
  • オプショナル
  • オーバーロード
  • デフォルト引数
  • メソッドチェーン
  • エラー処理

オプショナル

オプショナルは必要分だけにしよう。
KeychainAccess では、外に出す引数はなるべくオプショナルにしないようにしている。

オーバーロード

convenience init()
convenience init(service: String)

func set(value: String, key: String) -> NSError?
func set(value: NSData, key: String) -> NSError?

引数のデータ型が異なれば、同じメソッド名でも複数定義できるので便利。
Java みたい。
イニシャライザはすっきりするかも。

デフォルト引数を設定するとフルに補完されてしまうので不便。(これは Xcode の問題か?)
ただしクロージャの場合は例外。これは空実装をデフォルト引数にしておくと良い。

エラー処理

ObjCでは NSError をダブルポインタで渡すが、Swift ではEither型を使う。
独自のエラー型とかは作らずに、標準の NSError を使っていくのが良いでしょうとのこと。

その他

  • Mac の Keychain Access.app で見るとラベルとコメントを閲覧できるので、変更できる機能をつけておいた。
  • Playground をドキュメントに付属しておくと理解しやすい

まとめ

  • ObjC とは異なる Swift の性質を心得ておく
  • 公開用インターフェースの引数はできるだけオプショナル型を許容しない方が良い
  • オーバーロードを活用する
    • デフォルト引数と Xcode の補完の相性が悪い
  • クロージャは空実装をデフォルト引数にしておくと良い
  • エラーは Either 型で返す
  • 独自のエラーではなく標準の NSError を使う
  • ライブラリで提供する場合は Playground を同梱してあげると親切

『let UIWebView as WKWebView』

 ヤフー株式会社 佐野岳人氏

資料

http://techblog.yahoo.co.jp/ios/let-uiwebview-as-wkwebview/
http://www.slideshare.net/taketo1024/let-ui-webviewaswkwebview

WKWebView

  • Safari と同じエンジンで JS が速い!
  • ページジェスチャ対応
  • プログレス対応
  • iOS 8 以降

インターフェースは UIWebView と似ているが互換性はない。デリゲートが2種類ある。

WKWebView と UIWebView

WKWebView のメリットは速度。できる限りは使っていきたいが、iOS 7との互換性を考えて UIWebView も分岐して実装したい。

バージョン分岐処理を入れすぎると本来のコントローラの役割が不明瞭になってしまう。更に古いコードが山積して最終的には手に負えなくなる恐れがある。 ハウルの動く城のような実装はできる限り避けたい。

下位互換は隠蔽するのが理想

  • コントローラ、モデルなど上層からはバージョン分岐を意識させないようにする
  • 混み入った分岐はまとめておいて、分離できるようにする
  • 広範囲で使用されるなら依存は最小限にする

WKWebView と UIWebView の分岐処理を隠蔽する方法

ラッパーで包む方法では全メソッドに分岐が必要なので、非現実的。

Objective-C を利用して、UIWebView に WKWebView のフリをさせるアプローチ。

Objective-C のプロトコルでインターフェースを定義する

WKWebView のインターフェースを例えば WKWebViewProtocol という形で宣言しておき、WKWebView, UIWebView それぞれでカテゴリ拡張を行い、このプロトコルに適合させる実装を行う。
そして UIWebView の方に足りない分のメソッドを実装する。

注意点

  • UIWebView では原理的にできないこと(履歴を取得するなど)は妥協が必要

まとめ

  • WKWebView は高速なので積極的に使う
  • UIWebView には WKWebView のフリをさせる
    • 下位互換は隠蔽してコントローラ本来の役割を明確にする
    • Objective-C で WKWebView のインターフェースをプロトコルで定義し、カテゴリ拡張で実装する
  • UIWebView には原理的にできないことは妥協する
  • デリゲートはそれほど依存しないので普通に実装しても良い
    • Yahoo! Smart Search では普通に利用する方針をとっている

『通信のパフォーマンス改善』

 Wantedly inc 杉上洋平

資料

http://www.slideshare.net/susieyy/ios-ios-44665266

海外には通信品質が悪いところもある

New Relic Mobile, PonyDebugger で分析した。

PonyDebugger
https://github.com/square/PonyDebugger
http://qiita.com/edo_m18/items/d0c42a988010e1504f1c

  • JSONよりも画像の容量が多かった
  • 無駄な画像リクエストが見られた
  • 欲しい順番で画像取得が行われていない

通信量の大半を占める画像まわりを改善しよう

SDWebImage の仕組み

内部では NSOperationQueue で通信キューを管理。上から順に通信を処理していく。
キャッシュは二重に行われる(メモリキャッシュ、ディスクキャッシュ)

これらに優先度を設定できるようにカテゴリ拡張を行ったとのこと。
SDWebImage のバグを見つけて Pull Request を送ったら反映されたとのこと。

SDWebImagePrefetcher

画像先読み機能。

画像取得を中止

画面遷移時には遷移元の画像取得を中止する。

- (void)sd_cancelCurrentImageLoad;

その他のパフォーマンス改善策

  • Facebook では画像の9割にWebPを採用。SDWebImage も対応しているのでこれに倣ってみる
  • 通信帯域が悪ければ画質を下げてみる
  • 通信開始・終了の経過時間と画像サイズから通信帯域を推測するプログラム
  • 最大サイズからキャッシュ画像をチェック

  • MessagePackでJSONを圧縮

  • SPDYで通信コネクションをまとめる

  • 通信帯域による同時接続数を調整

確認方法

iOS のデベロッパ機能で通信速度をシミュレートできる。(「設定」 > 「デベロッパ」)

まとめ

  • 高速通信環境が整っていない地域もある(特に海外)。アプリを提供するならこれらを無視するのはよくない
  • 通信量の大半を占める画像の通信を見直し最適化する
  • SDWebImage のような画像取得通信を行うライブラリを活用する
  • 画像はキャッシュしておく
  • 不要になった通信は中止する(できるようにしておく)
  • サービス全体で WebP の採用を検討する
    • WebP は「ウェッピー」と読むらしい
  • JSON を圧縮する
  • 通信処理自体を最適化する
  • iOS のデベロッパ機能を活用して、低速通信をシミュレートする

『効率的なアプリ開発のベストプラクティス』

 グリー株式会社 矢口裕也氏

資料

http://www.slideshare.net/yayugu/ss-44667286

UX こだわりたい

UITableView+Updates でセルの更新を行うと滑らかで良い感じ。
いろいろアニメーションとかさせてみたり。(実行コストとの天秤)

UI の実装コスト

年々楽になってきている。効率的に実装するには作業量を減らせるのが良い。

  • Auto Layout
  • Storyboard
  • Self Sizing Cell

通信・APIの定義次第で工数が減る

やることを減らす=サーバーに任せる!

  • APIは共通化・RESTにこだわりすぎると(原理主義的になりすぎると)、クライアント側では通信量が増えてしまうことも
    • 美しいRESTが必ずしもクライアント側にとって良いとは限らない
    • 必要に合わせて API を統合してリクエスト数を減らす
  • Mantle, JSON Model に合わせて JSON を出力してもらう
  • クライアント側で画像以外のキャッシュを持たない

サーバーエンジニアを説得

現実、なかなか難しいことも。

  • パフォーマンス向上などのメリットを説明
    • 例えばリクエスト数4本が1本にまとめられると UX の向上につながる
  • クライアント側の大変さを説明
  • サーバーも自分で書いてみる

レガシーサーバーを触りたくない場合にはプロキシサーバーをたててしまうというのも。

まとめ

  • API の設計の「美しさ」が必ずしもクライアント側にとっても美しいとは限らない
  • クライアント側にとっては、API はまとめらた方がリクエストが減って良い
  • 情報はなるべくサーバー側に持ち、クライアント側の実装を減らす
  • サーバー側、クライアント側お互いに補完し合って開発することが大切

『WatchKit を実際にさわってみてわかったこと』

 フリーランス 堤修一氏

資料

http://d.hatena.ne.jp/shu223/20150214/1423901142
https://github.com/frosty/Flipbook

WatchKit アーキテクチャの基本

  • 親アプリの Extension で提供される
  • コードは iPhone で実行される
  • WatchKit App は基本的に表示のみを行う

アニメーション

Static なアニメーション

WatchKit App 内の Asset Catalog 内の連番画像を使用する。
10fpsは余裕。30, 60fpsもたぶんいける。

Dynamic なアニメーション

setImageData: しか使えないのでパフォーマンスが低下してしまう。

フレームごとに UIImage を作ってタイマーで回してみるが、速度は明らかに遅い。(デモ)
HIG によればキャッシュしてはダメだということなので、Animated Image を使用する。

UIImage.animatedImageWithImages()

テキスト入力:スマートリプライと音声入力の方法

presentTextInputControllerWithSuggestions というメソッドを使う。
フレーズの配列を渡し、入力タイプを指定する。

UI の実装について

  • ダイアルの描画方法
    WatchKit では Core Graphics 描画ができない。Apple のサンプル "Lister" では画像の細切れをあらかじめ用意しておいて、それをパラパラアニメーションさせる原始的な実装らしい!

  • カスタムフォント
    iOS と同様。

  • オーバーレイ表示
    WKInterfaceObject は UIView みたいに重ねてオーバーレイ表示できないので、バックグラウンド画像でそれっぽくする。

  • 座標
    frame.origin や UIEdgeInsets に相当するものがないので、表示位置を変えたい時は、WKInterfaceGroup でマージン用の空オブジェクトを配置して対応。
    Size Classes には対応している。

まとめ

  • WatchKit App は表示用
    • Extension で提供されるので、iOS 側に親アプリが必要
  • アニメーションにはいろいろ制約がある
    • 基本的に連番画像をパラパラアニメーションする手法をとる
    • UIImage のメソッドを利用できる
  • Core Graphics は使用不可
  • オーバーレイ表示に制約があるので背景画像で誤魔化す
  • 座標を操作できない?ので、マージン用の空オブジェクトを詰めて対応

WatchKit は iOS の感覚でいるといろいろ罠にはまりそうで、これらの知見は非常に参考になりました。アニメーションまわりに関しては連番画像ではなくもう少しなんとかならないのかな、という印象です。

『長生きするために心臓に悪いリリースはもうやめよう』

 クックパッド株式会社 所友太氏

資料

https://speakerdeck.com/tokorom/chang-sheng-kisurutamenixin-zang-nie-iririsuhamouyameyou
https://github.com/kishikawakatsumi/xcjobs

リリースボタンを押す際、In App Purchase はちゃんと動いているかなど、不安が残る。

サブミット前後でどういう確認を行う?

  1. プログラミングしながらデバッグ
  2. AdHocをTestFlightなどで配信、テスト
  3. プロモーションコードでテスト
    • Appleの審査終了後に行える
  4. iTunes Conenct の Internal Testers

    • Appleの審査が始まる前に行える
    • 課金はサンドボックス

3, 4 の確認も必要だよね。

Internal Testers でチェック

2014年秋頃から使えるようになった機能。App Store 公開用のアプリ(iTunes Connect にサブミットしたアプリ)を TestFlight でテストできる。
ただし、iOS 8以降で、25人までという制限がある。

Internal Testers vs. CI

CI が対応する範囲は (2) の部分なので、両方使っていくのが良い。
CIで自動化しておいて、Internal Testers は最後に行うのが良いのかもしれない。

万が一の事故のために

  • 後から見返せない情報はバックアップしておく
    • Build Details (keychain-access-groups など)
  • App Store に公開されていた過去バージョン
    • 実際に公開されていたipaを保管しておこう

まとめ

  • Internal Testers (TestFlight) で最終確認する
    • 審査なし
    • iTunes Connect にサブミットしたバイナリでテスト可能
    • iOS 8以降
  • CI も活用する
  • iTunes Connect 上のデータは補完しておくと後で役立つかも

『エンジニア戦記 ~ 小さなチーム 大きな未来 ~』

 クラスメソッド株式会社 平井祐樹氏

資料

http://www.slideshare.net/yukihirai52/ss-44668339
http://www.oreilly.co.jp/books/9784873116860/

iOS アプリを開発する上での Web API あるある

HTTP ステータスコードで返してくれない

{
"header" : { "status" : "success" },
"response" : { "topics" : [{...}]}
}

に header という形でエラーを含めてしまうと、クライアント側は200で通信成功してるのに(success block など)そこでエラー処理が必要になって気持ち悪い!

確かに success でエラー処理を行うのは気持ち悪いのですが、別途 HTTP ステータスコードが返ってくるのであればこの限りではないのかな、とも思いました。その場合は API 独自のエラーなどはこのような形で含まれることもあるのではないでしょうか。その辺りは各種プロダクトの設計次第かと。

フィールド名に整合性がない

"topics" : [{
    "topic_id" : 1,
    "topic_title" : "..."
}]

命名としてこの "topic_" は本来はいらないのに、この JSON に倣ってモデルクラスを書くとインターフェースが格好悪くなってしまう。

@interface Topic : NSObject

@property (nonatomic) NSInteger topicId;
@property (nonatomic) NSInteger topicTitle;

@end

これでは『トピックトピック』となってしまう!

コンテンツごとにエンドポイントがある場合

ある画面で必要なコンテンツをすべて取得するのに、API を複数叩く必要がある。クライアント側の処理が大変なことになるので、画面ごとに API をまとめられるとすごく嬉しい。

画面のAPIはひとつにまとめたい "One Screen, One API Call."

まとめ

  • 文句を言うのは簡単。お互い改善案を提案し合えるようにする
    • クライアント側は Web API を学ぶ
    • サーバー側はアプリの流儀を学ぶ
  • Web API の流儀が必ずしも正解とは限らない。提供するサービスの UX を考えるなら、API の設計もそれを意識したものにする必要がある
  • Web API The Good Parts を読んで勉強する
  • "One Screen, One API Call."

『まだiOSでリッチな演出に疲弊してるの?』

 面白法人カヤック 布田隆介氏

貞子アプリとかのリッチな演出には疲弊する……

  • Core Animation
    • 大量のオブジェクトは難しい
  • SpriteKit
  • Unity, Cocos-2d
    • ネイティブ機能のためにプラグインを作るのが大変
    • 3D演出などは得意
  • 最終手段で動画

などいろいろ手段はある。

SpriteKit は劣化版 Cocos-2d ではなかった

SpriteKit をアプリの演出に利用できるか?

  • 標準フレームワークなのでインストール不要
  • Xcode でプレビューしながら簡単に編集できる
  • API が UIKit に近い
  • 他のゲームエンジンに比べ、 UIKit との親和性がとても高いので利用しやすい

使い方

  1. SKScene のサブクラスでパーティクルなどの効果を実装
  2. SKView を UIView に addSubview() する
  3. Scene を実行

メリット

  • Apple提供の安心感
  • 既存のコードを汚さずに導入可能
  • デザイナーも触れる

注意点

  • UIView の上に透明の SKView を乗せて、SKView のタッチイベントを無効化(userInteractionEnabled=false)することでイベントを UIView に伝播させる
  • SKView の座標系は左下原点でY軸が UIView とは反転する
  • パーティクルは重い
    • SKView を小さくするとエフェクトも小さくするので軽くなる

まとめ

  • SpriteKit は劣化版 Cocos-2d ではない
  • UIKit と親和性が高く、UIKit ベースのアプリの演出をリッチにさせる手段としてとても有用
  • 導入コストが小さい
  • Xcode のプレビュー機能を活用すると簡単に実装できる
  • SKView を透過させ、タッチイベントを UIView に伝播させる

今まで SpriteKit の有用性がよくわからなかったのですが、UIKit ベースアプリの UI 演出に利用するという観点で見たらとてつもなく良いフレームワークに思えてきました。インターフェースが UIKit に近いですし、何より Apple 提供という安心感は大きいと思います。

Prott

https://prottapp.com/ja/

Good Patch のプロトタイピングツール。
Web 上で iOS や Apple Watch などのプロトタイピングがすぐ行える。端末と同期できる。

デザイナーとのコミュニケーションに有用そう。