try! Swift San Joseの作業メモ

WWDC18 に付随して行われた try! Swift San Jose に参加してきた。前半は Swift コミッターによるパネルディスカッション、後半は Open Source Swift にコントリビュートするというワークショップだった。このワークショップを通して apple/swiftPull Request を送ることができた。

最近読んだ id:higepon さんの ログのすすめ をとても良いと感じていて、ワークショップの作業はログを書きながら行ってみた。ログを残すことによって、自分が今取り組んでいる課題は何か、次に行うべき作業は何か、かなり明確にすることができた。特に Swift コンパイラという普段自分が扱っているコードベースとは全く異なる環境ではかなり助けになる実感があった。 せっかくなので、その時の作業メモを残しておく。


バグチケット

https://bugs.swift.org/browse/SR-7844?filter=10451

<stdin>:3:3: error: computed property must have accessors specified
  }
  ^

こうしたい

<stdin>:3:3: error: subscript must have accessors specified
  }
  ^

作業ログ

# ゴール

- [x]subscript の diagnostics が computed property になっているのを修正する
   -  [x]どういう時に出るエラーか
        - getter がない時に出る

# 分からないこと

- [x] 開発環境
    - Xcode or Vim?
    - どっちでもいい
- [x] デバッグの仕方
    - バグを再現するテストを書いて、直ったことを確認する
    - PRにはテストが必要
    - テストは短ければ短いほどいい
- [x]テストの書き方

# やること

- [x] issue に自分をアサインする
- [x] bug をバイナリで reproduce する
    - ビルドした swift を実行する
        - <unknown>:0: error: Swift does not support the SDK 'MacOSX10.13.sdk’
        - xcode-select で Xcode10beta見るようにしたら直った
- [x] テストを動かす
- [x] バグを再現するテスト書く
        - test/decl/subscript/subscripting.swift 173行目
- [x] computed property の方のテストが壊れていないことを確認する
        - test/decl/var/properties.swift 379行目
- [x] どこをどうやって修正するか
    - include/swift/AST/DiagnosticsParse.def
        - 251行目、プレースホルダを使うように文言を修正する
        - "%select{variable|subscript}0 must provide either a getter or “ こういうやつ???
    - [x] %select を使って修正する
        - https://github.com/apple/swift/blob/master/docs/Diagnostics.md
    - [x] 呼び元で引数を渡す
        - lib/Parse/ParseDecl.cpp
            - computed propertyとsubscriptを区別する
            - bool Parser::parseGetSetImpl 多分ここにisSubscript を渡さないといけない
            - static void diagnoseRedundantAccessors の引数に isSubscript というのがある (lib/Parse/ParseDecl.cpp 4016行目)

- [x] 自分の環境に fork して clone する
- [x] 自分がforkした方に修正を入れる
- [ ] 自分がforkした方でビルドする
- [ ] 自分がforkした方でテストを通す
    - [x] fork し直すのではなく、git の remote origin を変更した
- [x] PRを作る

このようにゴール、分からないこと、やることのアウトラインを先に書いて、作業を進めながら詳細を書き足していった。

swiftc のビルドエラー 'libxml/xmlreader.h' file not found について

swiftc を久しぶりにビルドしたら以下のエラーが出た。

/Users/enomoto/.ghq/github.com/apple/llvm/lib/WindowsManifest/WindowsManifestMerger.cpp:21:10: fatal error: 'libxml/xmlreader.h' file not found
#include <libxml/xmlreader.h>
         ^~~~~~~~~~~~~~~~~~~~

結論を書くと、 libxml 配下のファイルがなくてビルドエラーになる場合、Command Line Tools をインストールできていない。Xcodeのバージョンを上げたので、インストールする必要があった。

Command Line Tools のインストール

$ xcode-select --install

再度ビルド

$ ./swift/utils/build-script -Rt

無事ビルドが通った。

環境

WWDC18に参加した

f:id:enmtknt:20180603131544j:plain

6月4日〜8日にカリフォルニア州サンノゼで開催されたAppleの開発者向けカンファレンス、WWDC18に参加してきた。WWDCは今回が初めての参加で、他では得がたい経験をたくさんすることができた。 今回、渡航準備をするにあたって以前WWDCに参加した方のブログ記事を参考にさせてもらったので、この記事もこれから参加する方に役立つ内容にできたらと思う。

良かった事

WWDCのお祭りのような雰囲気を生で体験できる、最新の情報を現地で得ることができるというのは魅力的だが、以下のような点が現地に行ったからこそできた経験だと感じた。

  • Appleのエンジニアに直接質問できる
  • 他のエンジニアと交流できる
  • 情報収集のアンテナを得た
  • 業務にとらわれない集中した時間

Appleのエンジニアに直接質問できる

会期中はAppleのエンジニアに直接質問できるラボが開催される。仕事で解決できず困っていた事象について相談しに行ったところ、あっさりと解決してしまった。技術的な質問以外にも、アプリのデザインに関するアドバイスを受けられたり、初心者向けのラボもあり、Appleのエンジニアに直接質問できる貴重な機会だった。後述するtry! Swift San JoseでもSwiftコンパイラチームのエンジニアから直接手ほどきを受けることができた。

他のエンジニアと交流できる

現地で沢山のエンジニアと知り合うことができた。技術的な会話をしたり、普段どのように開発をやっているかを話したり、情報交換をした。話を聞いたところ多くのエンジニアが会社負担、業務扱いでWWDCに参加していて、そういう文化がもっと当たり前になればいいと思っている。ちなみに僕も今回の渡航費と参加費は会社に負担してもらった。

情報収集のアンテナを得た

オフィシャルのドキュメントがなんだかんだ一番参考になるということ、WWDCのビデオをちゃんとチェックすれば詳細な情報を得ることができるということを改めて実感した。普段ついQiitaやStack Overflowを見がちなので、一次情報をしっかり確認する癖をつけたい。

業務にとらわれない集中した時間

人によるとは思うが、普段1つの技術について突き詰めて考える長い時間を確保するのは難しいと思う。普段の業務だったり、生活に関するあれこれだったり。そういうものにとらわれずに色々考えを巡らせたり、新しい技術を試す期間を持つことができるというのはとても貴重なのではないか。

f:id:enmtknt:20180604130033j:plain

準備と現地での過ごし方について

航空券

渡航の際の航空券について。当選が決まり次第なるべく早く押さえた方が良い。僕はHISでLA経由のチケットを手配してもらった。またアメリカへの渡航に際してはESTAの登録が必要になる。これは申請から登録まで少し時間がかかるので早めに登録を行っておくと良い。インターネットで簡単に申請できる。

宿

世界中から開発者がサンノゼに集まるので、これも当選が決まり次第なるべく早く押さえた方が良い。当選してから数日後に探し始めたが目ぼしいホテルはほとんど埋まっており、Airbnbで予約した。宿泊した場所は会場から車で10分程度のところだったが、とても綺麗で過ごしやすかった。必ずしもホテルが良いとは言い切れないように思う。会場から近い方が楽なのは間違いない。

移動手段

現地で会った人たちでは、UberLyftを使っている人が大多数だった。僕はレンタカーを手配したが、アメリカで運転するのはとても神経を使うし、借りるにもそれなりのお金がかかる。滞在の後半はUberを何度か使ったが、すぐに来てくれるし料金は安いし、すごい体験だった。
ちなみにレンタカーを運転する場合は国際免許が必要になる。免許センターに行けば、手続きだけで即日発行することができる。

インターネット環境

iijmioの海外旅行用のSIMを事前に契約していったが、結果的にはあまり筋が良くなかった。早々に容量が足りなくなり、AT&Tのショップに足を運んでSIMを契約した。国内でT-Mobileのツーリストプランを契約してきていた人もいた。 ちなみにWWDCの会場はWi-Fiが飛んでおり、普通にインターネットができる。作業スペースも大きく確保されていて、そこに行けば有線でネットワークを使うことができる。

持ちもの

発表された新しいOSをインストールするために、以前使っていたiPhone 5s, 6sを持って行った。それ以外は Quoraの記事 を参考に荷造りをした。また会場内はかなり強めに空調が効いていて、夜は冷えるので、春秋に着るぐらいの上着は持っていくとよい。

お金

サンノゼはほとんどの店がクレジットカードに対応しており、現金を使う機会はあまりなかった。クレジットカードがあるならば、不測の事態に備えて幾らか持っておくくらいで問題ないと思う。

日程、レジストレーション

WWDC本編は月曜から金曜までの開催となる。入場のためのレジストレーションは開催前日の日曜から毎日可能だ。月曜は朝からKeynoteがあるため、Keynoteで良い席を確保するために早朝から並ぶなら、日曜日に必ずレジストレーションしておくことを勧める。

周辺イベント

WWDC開催期間中は周辺で様々な技術イベントやミートアップが開催されるので、事前に調べて参加登録しておくと良い。僕は最終日の金曜は try! Swift San Jose に参加した。try! Swift San JoseではSwift open source projectにコントリビュートするというワークショップが行われ、以前からSwiftコンパイラのコードを読んだりしていた自分としてはとても興味が惹かれるイベントだった。AppleのSwiftコンパイラチームの方や日本人のメンターの方に質問しながら、Swiftコンパイラにコントリビュートすることができた。この時の話については別エントリでもう少し細かく振り返ろうと思っている。

またカンファレンス以外に、WWDC渡航した日本人エンジニアのミートアップや、現地で働く日本人エンジニアの飲み会に参加させてもらう機会があった。こういった場で多くの新しい出会いがあったので、積極的に参加すると楽しいと思う。

おわりに

今回、幸運にも当選したことや家族や職場の協力があって初めてWWDCに参加することできた。来年以降ももし機会があればまた参加したい。

f:id:enmtknt:20180605154622j:plain

WWDC18 Keynoteメモ

WWDC18 Keynote

Keynoteの内容を書き下したメモ
https://developer.apple.com/videos/play/wwdc2018/101

tl; dr

  • 新しいハードの発表は無し
  • 今回のリリースは最適化、セキュリティの改善を強調しており、OSの基盤を固めるリリースと言える
  • AR, 機械学習分野の強化がなされた(ARKit 2, Creating ML, Metal 2)

iOS

iOS12

  • 大幅な最適化がなされた
    • iPhone 5Sのような古い端末でも滑らかに動くことを強調していた
    • iOS 11よりも速いとのこと
  • ARアプリ
    • ARKit 2
    • メジャーアプリ
      • カメラを起動して、画面に写ったものを採寸できる
  • 写真アプリ
    • search, suggestion, for you, share
    • 機械学習を基盤にした各種機能が追加される
  • SiriKit Shortcuts
    • キーワードを登録できる
    • Siriからアプリ操作するショートカットを作成できる
  • Shortcuts app
    • IFTTTみたいに複数のアプリをピタゴラスイッチのように連携できる
    • 以前買収したWorkflowが本家に取り込まれた形
  • ニュースアプリ
    • personalized, secure, trusted
  • 株価アプリ
    • ニュースアプリと連携できる
  • ボイスメモアプリ
    • iPadでも使えるようになった
  • iBooks
    • Apple Books になり、アプリが一新
    • ebook, audio book
  • CarPlay
    • 新しいマップアプリがサポートされた
    • google mapなど
  • Do Not Disturb
    • 特定の期間通知をOFFにすることができる
  • Grouped Notification
    • 通知をまとめて表示する
      • アプリ毎
  • Screen Time

    • アプリの起動時間、通知を確認できる、アプリの使用に時間制限をかけられる
    • 子供のアクティビティを監視できる
    • 子供の端末をより安全にセットアップできる
  • Animoji, tongue

    • iMessageで動くアニメを送れるように
  • Memoji
    • Animoji をカスタムして自分の似顔を作れる
  • FaceTime
    • 32人まで同時に使えるようになった

watchOS

watchOS 5

  • competition, Awards
    • 友達と競える
  • Walkie-Talkie
    • AppleWatch を使ってメッセージを送れる
  • WatchOSだと "Hey Siri" 言わなくてよくなる
  • WebKitサポート
  • Podcasts アプリがリリースされる
  • 学生向けのID管理機能がリリースされる、6大学に対応

macOS

macOS Mojave (モハべ)

  • Dark Mode を搭載する
  • Dynamic Desktop
    • 壁紙の色が時間帯によって変わる
  • Stacks
    • デスクトップのアイコンをまとめられる
  • Gallery view, Quick Actions
  • Quick Look , macOSのビューアアプリで画像、動画pdfをさくっと編集できる
  • Screenshots , video recording
    • iPhoneMacのスクショをシームレスに扱える
  • ニュース、株価、ボイスメモ、ホームアプリがMacアプリに提供される
  • macOSFaceTimeも 複数人に対応
  • セキュリティの強化
    • ユーザの設定次第でWebサービスからのトラッキングを完全にOFFすることができる
    • 強度の高いパスワードを自動生成し、管理する機能が強化された
  • Mac App Storeがリニューアル

tvOS

Technologies

ReSwiftをためした所感

現在仕事で開発中のiOSアプリにReSwiftを導入できないか検討した。

結論としては今回は導入を見送ったが、良いと感じた部分が沢山あったので雑な作業メモを転記する。

ReSwift とは

Redux は複雑な状態を管理するために生まれたJS発祥の技術

そのRedux をSwiftに移植したものがReSwift

ReSwift/ReSwift: Unidirectional Data Flow in Swift - Inspired by Redux

こちらに大変わかりやすくまとまっている

ReSwiftでアプリの状態管理 / Reactive Swift Meetup // Speaker Deck

モチベーション

  • アプリ全体で共有する状態の管理をうまくしたい
  • グローバルなスコープのシングルトンにアプリの様々な箇所からアクセスするのは不健全な気がした

インストールから簡単に使うところまでの作業メモ

まずは以下のリポジトリをそのままアプリに移植し、それを拡張していった

ReSwift/CounterExample: Demo Application of Unidirectional Data Flow in Swift, Built with ReSwift

ReSwift を Cartfile に追加

$ carthage update --platform iOS --no-use-binaries

ReSwift の設定をプロジェクトに反映

AppState を作成

  • アプリ全体の状態を持つ
  • Action からしか変更できない

CounterReducer を作成した

  • counterの状態を変更する Reducer
  • AppState を返す状態を持たない関数

Actions を作成した

  • Action protocol を実装した struct として定義する

  • subscribe すると、最初に newState が呼ばれて現在の state が降ってくる

  • 最初の state は 特に action をdispatchしていないので、ReSwiftinit 型になっている
  • action を dispatch すると、その結果また newState が呼ばれて状態の更新が通知される
  • subscribe しないで dispatch することもできる

    • 状態は変更できるが、newStateに通知されない
  • ネットワークエラーでアラートを出したいときはどうする?

    • ErrorActionを発行して、subscribeしているViewControllerで新しいstateに応じてエラーを表示する

アプリアーキテクチャに関する考察

  • MVP(Clean Architecture) に適用する場合

    • ビジネスロジックをUseCaseの代わりにActionに書いて、それをPresenterから呼ぶ
    • StateはPresenterでsubscribeする
    • ビジネスロジックは Action にとどめておいて、 Reducerは状態の管理に徹する
    • newState に降ってくるイベントは今まで通りViewControllerにdelegateする
  • Redux にすることで、今までdelegate とかクロージャでばらばらに受け取っていたコールバックを1つのメソッドで、1つの状態として扱えるようになる

引数とメソッド呼び出しについて

  • データを fetch するaction で引数にデータを渡さなくても、クロージャのstate を通じて、欲しい状態を取れるようになる
  • ようするにグローバル変数と変わらないのだが、状態の変更 をAction, Reducer を用いるよう制限することで、データの流れを把握しやすくする

Promise を使った非同期処理の連結

Reducer の分割について

How could i use multiple reducer in Reswift 4.0.0 · Issue #241 · ReSwift/ReSwift いいかんじ

ユニットテスト

まだ書いたことはないが、Action は基本的に状態を持たないのでテストは書きやすそう

デバッグのしやすさ

  • クラッシュした時のStateをキャプチャできるので、再現してデバッグするのが簡単になるのではないか
  • ReSwift Recorderという仕組みもある

やめた理由

  • 今後自分以外の人も保守することを考えると、ReSwiftにロックインされるのはあまり良くない
  • 今開発中のアプリは大量の状態を持っているわけではないので、現状の要件にはそこまでマッチしていない
  • newState の取り回しが若干面倒な気がしている
  • pros が cons を上回るなら導入も吝かではない
    • もう少し練度が上がればスムーズに使っていけるのかもしれない

SwiftGenの使い方を調べた

仕事で新しいプロジェクトに導入したく、 SwiftGen の使い方を調べていた

環境

  • Xcode 9.2
  • SwiftGen 5.3.0

SwiftGen とは

https://github.com/SwiftGen/SwiftGen

プロジェクトのリソース用のSwiftコードを自動的に生成し、タイプセーフな使用を可能にするCLIツール 具体的には以下の5つに対応している

  • Asset Catalogs
  • Color
  • Font
  • Storyboard およびそのシーン
  • Localizable.strings

モチベーション

iOS開発では、前述のようなリソースにアクセスするには文字列を使う必要があるが、それらをタイプセーフにすることで人的なエラーを排除することが目的

導入方法

1. ディレクトリ作成

生成されたコードを格納するディレクトリを作成する

2. Cocoapods

iOSアプリで使用する場合、 Cocoapodsを使ってインストールが可能。

Podfileの内容は以下のとおり

target 'YoutTargetName' do
  use_frameworks!
  pod 'SwiftGen'

end

3. swiftgen.yml

プロジェクトルートに swiftgen.yml を作成する 一例として、以下のように書ける

strings:
  paths: Resources/Base.lproj/Localizable.strings # パスを指定する
  templateName: structured-swift4 # Swift 4 を使用
  output: CodeGenerated/strings.swift # どこに生成したファイルを格納するか
xcassets:
  paths:
   - path/to/Assets.xcassets
  templateName: swift4
  output: CodeGenerated/assets-images.swift
storyboards:
  paths:
   - path/to/Storyboards
  templateName: swift4
  output: CodeGenerated/storyboards.swift
colors:
  paths:
   - path/to/colors.json
  templateName: swift4
  output: CodeGenerated/colors.swift

4. スクリプトの実行

Run Scriptを設定するやり方と、コマンドラインで実行するやり方の2種類が考えられる

Run Script の設定

TARGETS -> プロジェクト名 -> Build Phrases -> New Run Script Phrase を追加して、以下のスクリプトを実行するように設定する

"${PODS_ROOT}/SwiftGen/bin/SwiftGen"

コマンドライン

プロジェクトルートで

$ Pods/SwiftGen/bin/SwiftGen

を実行する

SwiftGen と R.swift の比較

SwiftGen に近いツールでよく知られたものに R.swift がある

機能面はほぼ同等で、以下のような違いがある

SwiftGen R.swift
導入 やや面倒 簡単
制御 不要な機能は disable できる 全部入り
ビルド クラスがリソースごとに分かれているため、毎回全ビルドが走ることはない リソースファイルに増減がある度に R.generated.swift の全ビルドが走るので、大規模プロジェクトでは時間がかかる

好みの範疇と言えそうだが、 SwiftGen の方が取り回しが良さそうなので、 SwiftGen を使う予定

Sourceryの使い方を調べた

Sourceryの使い方を調べたので記録を残しておく

Sourceryとは

Sourcery は Swift のボイラープレートを自動生成するためのツール try! Swift Tokyo 2018における作者のトーク によると Sourcery は 5000 以上の実プロジェクトで使われていて、 Apple 社員のなかにもユーザがいるとのこと。

モチベーション

Swift は厳格な静的型付言語であるがゆえ、大量のボイラープレートが必要になる。例えばオブジェクト同士を比較するためのEquatableも開発者が実装する必要がある。1つのクラスであれば大した作業ではないが、クラス数が増えることで大変な手間となり、バグが混入する原因にもなる。それらを自動化するためのツールが Sourcery である。

利点として導入にリスクがなく、不要になったらテンプレートを削除すればOKであること、タイプセーフであることが挙げられる。

導入方法

Sourcery のリポジトリにあるサンプルプロジェクト を参考にするとよい。

1. ディレクトリ作成

以下のディレクトリをあらかじめ作成しておく

2. Cocoapods

iOSアプリで使用する場合、 Cocoapodsを使ってインストールが可能。

Podfileの内容は以下のとおり

target 'YoutTargetName' do
  use_frameworks!
  pod 'Sourcery'

end

3. Run Script の設定

TARGETS -> プロジェクト名 -> Build Phrases -> New Run Script Phrase を追加して、ビルドの度に以下のスクリプトを実行するように設定する

各引数に

を指定する

"${PODS_ROOT}/Sourcery/bin/sourcery" --sources "${SRCROOT}/YourProjectName" --templates "${SRCROOT}/Templates" --output "${SRCROOT}/CodeGenerated"

もちろんBuild Phrasesにこのスクリプトを追加せず、手動で実行する運用でも問題ない。

4. プロトコルの実装

AutoEquatable, AutoHashableなど自動生成するプロトコルを予めどこかに実装する。これをやっておかないとツールがエラーになり、生成に失敗する。

protocol AutoEquatable {}

5. ビルド

1 ~ 4 までの手順が完了すれば、ビルドする度にSourceryによるコード生成が行われる。

Templatesの書き方

テンプレートは Stencil という Django template, Mustache に似た記法を使って書く。

リポジトリ にサンプルがあるのでこの辺りから出発するのが良さそう。