その後のその後

iOSエンジニア 堤 修一のブログ github.com/shu223

「try! Swift」1日目の復習 #tryswiftconf

iOSのカンファレンス「try! Swift」がいよいよ昨日から始まりました。恥をさらすようですが、半分ぐらいのセッションでリアルタイムについていけませんでした。。


ので既に上がっている発表資料やレポート記事を参照しつつ復習をしていこうかと。(WWDCもリアルタイムでは理解できないのでいつもスライドpdfが出てから自分のペースで手を動かしながら勉強する、というスタイルでやってます)


オーバービュー的な話、考え方的な話はありがたく参考にさせていただきつつ、ここでは主に実装面のセッションについて復習していきたいと思います。

実践的クロスプラットフォームSwift / Practical Cross-Platform Swift

Realm の JP Simard さんの話。

SwiftはApple以外のプラットフォームでも利用できるようになりました。iOSアプリ以外でも好きなようにSwiftを書けます。この講演では、CocoaやObjective-Cの機能を犠牲にせずに、クロスプラットフォームでSwiftを用いるときの実践的な書き方、テスト・デバッグ手法、について解説します。


開発環境

まず開発環境の話。できるだけ統一したいよねーというので、次の3つが挙げられていました。

  • Xcode
  • Xcode + Toolchain
  • Docker + CLI + Editor


そういう選択肢があるよねという話としてはわかるのですが、何が腹落ちしなかったのか考えてみると、

  • この3つのメリット・デメリットがよくわからない
    • たとえば、Xcode単体だと何らかのプラットフォーム向けの開発時に困るという話なのか?それとも開発環境としてXcodeやMacに縛られたくないという話なのか?
  • Toolchainがよくわかってない
    • ([Xcode] > [Toolchains] というメニューがある)
  • Docker使ってCLI+好きなエディタで開発できますという話とかは、サーバーサイド開発とかで普段そうしてる人だとピンと来る話なのかもしれない

そもそも非マルチプラットフォーム(MacでiOS開発しかやってない)、エディタとかにもこだわりがない(Xcodeで不満がない)人間なので、とりあえず何がわからなかったのかを列挙できたのでいったんokとします。。*1

Swift Package Manager

なぜSPMの話がクロスプラットフォーム開発の話で出てきたのかよくわからなかったのですが、niwatakoさんの書き起こし記事 みて、

是非オススメしたいのはSPMを使う時に自分のコードを細かいプロジェクトに分けることです。


使いまわしやすいように細かく分けてSPMで管理しよう、という話だと解釈しました。違ってたらすみません。*2

Objective-C 依存

これもリアルタイムでそもそも何についての話なのか(依存性の話だということが)理解できないまま聞いてましたが、niwatakoさんの書き起こしで理解。

#if がたくさん必要になる。 アーキテクチャチェック、AppleFrameworkを使っていないか、Objective-Cランタイムを使っていないかなど。この辺離れていくしか無い。時間がたてば軽減していくと思われる。


今のところは大変そうだ。。(JPさん荒野の開拓ありがとうございます)

Q&A: クロスプラットフォーム&オープンソースなXcode

これもniwatakoさんの記事で理解。Darwin以外でも動くXcodeはオープンソースとして出るか?という質問だったらしい。で、回答としては、Xcode自体は出ないと思うけど、SourceKitとかほとんどのIDEサポートはオープンソースになってるし、クロスプラットフォームで使えるものもあるので、実質的には別プラットフォームでIDEサポートはできると思います、と。

平常心で型を消し去る / Keep Calm and Type Erase On

型を明確にすることがSwiftらしいやり方であると気づいた時、同時に時には型を消す必要があると分かります。この講演では、型とは何か、型を消すことが何を意味するか、なぜそうしたいかについて解説します。


あとで手を動かしてコード書いてみよう、と思ってたら既に @hkato193 さんが試されてて、


@norio_nomura さんがgistにアップされてました。

ありがたや。


こんな風に書けるのか。。

class AnyPokemon<PokemonType>: Pokemon {
    let _attack: PokemonType -> Void
    required init<U: Pokemon where U.PokemonType == PokemonType>(_ pokemon: U) {
        _attack = pokemon.attack
    }
    func attack(move: PokemonType) {
        _attack(move)
    }
}


で、こんな感じで使えると。

let pika = AnyPokemon(Pikachu())
let hito = AnyPokemon(Hitokage())
pika.attack(3)
hito.attack(3.0)

勉強になりました。


  • 別の登壇者の方の実装:

  • 関連トーク:

Swiftのエラー処理についての三つの話 / Three Stories about Error Handling in Swift

エラー処理は安全なコードを書く上で重要です。私のプレゼンテーションでは、主に私の経験と考えに基いて、また `Error Handling Rationale and Proposal` と swift-evolution のメーリングリストでの議論にも触れながら、 Swift におけるエラー処理の論点を整理します。" : "Error handling is important to write safe codes. In my presentation, I will organize the issues of error handling in Swift mainly based on my experience and thinking referring to `Error Handling Rationale and Proposal` and discussions on the swift-evolution mailing list.")


後ほど復習:

プロトコルと約束の地 / Protocols and the Promised Land

Swiftの設計はジェネリクスや第一級プロトコルなど言語の機能がアプリケーション開発のカギとなることを推進しています。しかし、Objective-Cから導入されたものを含む論理的パターンの多くは期待した通りには動作しません。多くの場合、Swiftの型システムは、プロパティをクラスとプロトコルの両方に拘束したりする素直なパターンとうまく動きません。この講演ではいくつかの課題に着目し、内部に潜む原因を議論し、対応策について考えます。


後ほど復習:

文化を調和させる / Blending Cultures

Swiftでアプリケーションを書くということはObjective-Cで書かれたアプリケーションをただSwiftに書き換えるだけでなく、Swiftの特徴や哲学を受け入れる必要があります。この講演では、標準的なMVCで構成されたテーブルビューを使用したアプリケーションをSwiftに書き換えるところから始まり、よりSwiftらしいコードにするために、関数型プログラミング、オブジェクト指向プログラミング、デザインパターン、プロトコル指向プログラミングの考え方を適用していきます。


まずは niwatako さんの書き起こし を読んで理解しようと試みたのですが、


・・・わからない。コードの意味、やってることそのものはわかるのですが、一枚一枚のスライドとその間にある「その心は?」的なところがわからない。。


ただ、結局何をやっているのか、というのは最後にひとことで要約されてました。

さて、何をしましたか、いろんな簡素化しました。変更しないコードを外に追い出しました。


実際にサンプルコードを書いてくれた方がいます。


このコード内の HandVC.swift という UITableViewController サブクラスを見ると、効果が一目瞭然です。

class HandVC: UITableViewController {
    
    private var dataSource = HandDataSource()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.dataSource = dataSource
        tableView.delegate = self
        navigationItem.leftBarButtonItem = editButtonItem()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    @IBAction private func addNewCard(sender: UIBarButtonItem) {
        dataSource.addItemTo(tableView)
    }
}


なんとこれで全部。肥大化しやすい VC がこうもスッキリするのかと。ちょうどVCを肥大化させてしまった個人プロジェクトがあるので、この考え方でリファクタリングしてみようと思います。

Core Animationで作る高度なグラフィックス / Advanced Graphics with Core Animation

理解はできたので復習は省略しますが、発表に関連する話で、Core Animation を使ったライブラリを公開しています。



カスタマイズ性のためにいろいろとプロパティが多くなってしまってますが、基本的にはシンプルで、

  • CABasicAnimation で scale をアニメーションさせつつ、
  • CAKeyframeAnimation で opacity をアニメーション

させてます。また複数のパルスを発生させるために、(スライドにも出てきた) CAReplicatorLayer を利用 してます *3


我ながらAPIがいけてないのですが、実装時間3分ぐらいでそれなりにインパクトのあるアニメーションを入れられるので費用対効果抜群です。自分でも、WHILL、Moff、BONX、iOS×BLE本のサンプル、その他iOS Samplerシリーズやハッカソンでの作品、プロトタイプ案件等々、Bluetoothや位置情報を使う場合にしょっちゅう利用してます。






近々Swiftでつくりなおそうと思ってます。(あ、ObjCです、すいません try! Swift なのに)

スマートホームのためのコード / Code for the Smart Home

上に同じく、理解はできたので復習は省略しますが、ちらほらタイムラインで見かけた意見について。



上記記事にも書いてあるのですが、HomeKit Accessory Protocol は次のような構造になっています。



対応デバイスも海外ではちらほら出てきている *4 ので、近々記事を書こうと思います。



*1:たぶん上記疑問に答えてもらっても、「なるほどー(ポカーン)」ってなりそう

*2:JPさんの英語がハキハキしてて何とかついていけそうな気がしてこの時点では同時通訳聞いてなかったので、たぶん聞き逃しまくってたのかと

*3:@dealforest さんプルリクありがとうございました!

*4:昨年WWDCでSFに行ってきたときに買ってきて、まだ触ってない。。