[iOS]リソースの管理・利用を型安全にするためにSwiftGenを導入する
新規でアプリを作ることになり、プロジェクトのリソースに対応したSwiftコードを自動生成して型安全な利用ができるようになるツールとしてR.SwiftではなくSwiftGenを使ってみたかったので導入してみました。
SwiftGenについて
SwiftGenの他のコードジェネレータと比べて差分を見てコード生成する点や再ビルドが不要な所、生成先及び生成元のパスやリソースの任意の選択等設定が柔軟にできる点が優位な点だと思います。ただ、R.Swiftより少し導入が面倒に感じました。それでもそれを上回るメリットを感じているので今回は過程を記事にしたいと思います。
インストール
インストール方法は複数あります。zipでダウンロードしたりCocoaPodsなど様々ですが、現在取り組んでいるプロジェクトではMintを導入していますのでMint経由でインスールすることにしました。
Mintでのインストールを行いたい場合6.0以上が条件です。Mintfileに以下のように記載します。
SwiftGen/[email protected]
mint bootstrap
でインストールします。
設定ファイル
SwiftGenはCLIツールとして提供されていて、設定ファイルを使用してパースする必要のある入力ファイルの種類に応じてパーサとそのパラメータを定義します。swiftgen.yamlを定義してプロジェクトのルートディレクトリに設置します。
xcassets: inputs: - Sources/Resources/Images.xcassets - Sources/Resources/Colors.xcassets - Sources/Resources/Assets.xcassets outputs: - templateName: swift5 output: Sources/Generated/Assets.swift strings: inputs: - Sourcese/Resources/Base.lproj filter: .+\.strings$ outputs: - templateName: structured-swift5 output: Sources/Generated/Strings+Generated.swift
static methodで定義されているので
L10n.Greeting.hello
のように使います。
swiftgen config init
で設定ファイルを作成できます。設定ファイルの記述が済んだらswiftgen config lint
で設定ファイルの検証が行えます。
実行結果を載せますがmint経由で実行しているのでmint runが付いていますが他の環境であれば不要です。
❯ mint run swiftgen config lint Linting swiftgen.yml > Common parent directory used for all input paths: <none> > Common parent directory used for all output paths: <none> > 1 entry for command strings: $ swiftgen strings --templateName structured-swift5 --output ProjectName/Generated/Strings+Generated.swift --filter .+\.strings$ ProjectName/Resources/ja.lproj > 1 entry for command xcassets: $ swiftgen xcassets --templateName swift5 --output ProjectName/Generated/Assets.swift ProjectName/Resources/Colors.xcassets ProjectName/Resources/Assets.xcassets
設定ファイルでなく直接オプションや引数に適切な値を渡すことでswiftgen runコマンドでファイル生成できますが、プロジェクトでは設定ファイルを使うケースの方が多いと思うので子細は説明しません。気になる人はドキュメントのConfiguration fileの節を参照されてください。
templateNameについて
SwiftGenはSwift製のStencilというテンプレート言語を採用しています。なので使用しているSwiftのバージョンに合ったテンプレートを選ぶことができます。この任意のバージョンを指定するために使用するのがtempleteNameです。
SwiftGenにはそれぞれのパーサ用のテンプレートがバンドルされているて通常はそれを使用するだけですが、テンプレートが使用するプロジェクトに合わない時には独自のテンプレートを作成できます。今回は新規プロジェクトへの導入ということで提供されているテンプレートを使いました。
templateName出力オプションを使って使用するテンプレートの名前を指定するだけです。しかし、バンドルされているテンプレートがあなたのコーディング規約やニーズに合わない場合は、独自のテンプレートを作成することもできます。SwiftGenのテンプレートカスタマイズのためのドキュメントも提供されています。
提供されているパーサーは以下です。
- Core Data
- Fonts
- Asset Catalog
- Colors
- Strings
- Interface Builder
- JSON, YAML
- Plists
Build Phases
自動生成されるファイルはGitの管理から外していて、ビルド時に生成されるようにしたいのでBuild Phasesに追加しました。Compile sourcesでターゲットを構築する過程でどのソースファイルをコンパイルすべきかをコンパイラに知らせますがその時点で生成されたファイルがないと困るのでRun SwiftGenというSwiftGenを実行するスクリプトをCompile sourcesより前に実行するようにしました。
mintを使用しているのでSDKROOTのunsetやmint経由で呼び出したりしていますが、プロジェクトによって書き換えてください。
XcodeのBuild Phasesでmintを実行する時の注意点 - Qiita
unset SDKROOT if which mint >/dev/null; then mint run swiftgen else echo 'warning: Mint not installed. Please install mint from https://github.com/yonaskolb/Mint' fi
Xibについて
Assets CatalogsやColors、Localizable.stringsに加えてInterface BuilderなどもSwiftGenに対応しているのですがxibは対応していません。既存でなければ個人的にStoryboardはあまり使うつもりがないのでxibを使いたいです。Reusableを使用するとXibでもStringベースのAPIから型安全なAPIに変更できます。
薄いライブラリだったのと、xib経由の初期化の型安全化はNibInstantiatable というprotocolを実装して使うことが多かったので今回は不要と判断して採用しませんでした。
このテーマは国内でも何度か記事になっているのとSwiftGenの説明とは関係がないので説明を譲ります。
まとめ
R.SwiftがあるのにSwiftGenが台頭して気になっていました。案件では既存でR.Swiftが導入されていたのでSwiftGenを業務で使う機会がなかったのですが、運良く仕事で使う機会に恵まれたので使ってみたという記事でした。
不要ならビルドが走らない以外にも柔軟性などメリットがあることが知れて良かったです。