SwiftGen とは
SwiftGen は、iOS / macOS アプリ開発の補助ツールです。リソース(アプリ内の画像やテキストなど)の扱いが楽になるソースコードを自動生成してくれます。(なお、同様のツールに、(R.java 風の)R.swift や rdotm などがあります)
例えば、以下のようなことができます。
// ツールなしの場合
let image = UIImage(named: "banana")
// SwiftGen を使った場合
let image = UIImage(asset: .Banana)
リソースの名前を文字列で書かなくてはならなかったところが、enum 定義値で書けるのがポイントです。
対応しているリソース
以下のリソースに対応しています。
- 画像
- 文字列(ローカライズ)
- Storyboard
- 色
- フォント
使い方
swiftgen images DIR
swiftgen strings FILE
swiftgen storyboards DIR
swiftgen colors FILE
swiftgen fonts DIR
それぞれのコマンドを実行すると、リソースに応じた Swift ソースコードが出力されます。
入力データ
- 画像 :
*.xcassets
- 文字列 :
*.strings
- Storyboard :
*.storyboard
- 色 : 色定義ファイル(JSON、XML、
*.clr
など) - フォント :
*.ttf
,*.otf
など
画像、文字列、Storyboard は、通常のアプリ開発で使われるリソースそのものを SwiftGen に読み込ませることができます。
色は、色定義ファイルを別途用意する必要があります。といっても、色名と RGB 値を羅列したシンプルな JSON ファイルを用意すればすみます。
利用側のコード
SwiftGen が生成したコードをアプリ内で利用する方法について述べます。
Images
2種類の書き方があります。
let image = UIImage(asset: .Banana)
let image = Asset.Banana.image
なお、macOS の場合は UIImage
でなく NSImage
となります。
Strings
2種類の書き方があります。
let title = tr(.AlertTitle)
let title = L10n.AlertTitle.string
Storyboards
// ViewController
let initialVC = StoryboardScene.Main.initialViewController()
let loginVC = StoryboardScene.Main.LoginViewController()
// Segue
performSegue(StoryboardSegue.Main.CreateAccount)
上記の initialViewController()
はちゃんと Storyboard を読んで適切な型で返してくれます(UIStoryboard
の instantiateInitialViewController()
は UIViewController
を返すので、自分で適切な型にキャストしなくてはならないですよね)。
なお、macOS の場合は、swiftgen のオプション --template storyboards-osx-default
をつけてコードを生成します。UIStoryboard
でなく NSStoryboard
に対応したコードが生成されます。
Colors
let titleColor = UIColor(named: .Title)
let titleColor = ColorName.Title.color
なお、macOS の場合は UIColor
でなく NSColor
となります。
メリット
SwiftGen を使うと、リソースの指定に文字列ではなく enum 定義値を使います。このため、リソース指定のミスがなくなるというメリットがあります(記述が間違っていたらビルド時にエラーになる)。また、補完入力もでき、コードが書きやすくなります。
また、Localizable.strings
を書くのは結構面倒なものだと思います。しかし、SwiftGen のおかげで、Localizable.strings
を書けばコードが書きやすくなるのですから、やっておこうという気持ちになります。このような、心理的負担の軽減はなかなか馬鹿にならないメリットだと思います。
生成コードを見てみる
SwiftGen が生成するコードがどんなものなのか、簡単に確認しておきます。以下、Images を見てみます。
文字列が enum の case
として定義されているのがわかります。
enum Asset: String {
case Banana = "banana"
case Apple = "apple"
}
その enum を使って init
が行えるように extension が書かれています。
extension Image {
convenience init!(asset: Asset) {
self.init(named: asset.rawValue)
}
}
// 利用方法
let image = UIImage(asset: .Banana)
また、enum のプロパティも定義されています。中では先ほどの init
を呼んでいます。
enum Asset: String {
var image: Image {
return Image(asset: self)
}
}
// 利用方法
let image = Asset.Banana.image
特に難しいことはなく、シンプルなコードを生成してくれていることが分かります。
コード生成テンプレート
生成するコードはカスタマイズできます。生成コードのテンプレートを用意すれば良いです。
標準でいくつかのテンプレートが用意されています。swiftgen templates list
で一覧できます。
colors:
custom:
bundled:
- default
- rawValue
- swift3
images:
custom:
bundled:
- allvalues
- default
- swift3
storyboards:
custom:
bundled:
- default
- lowercase
- osx-default
- osx-lowercase
- swift3
- uppercase
strings:
custom:
bundled:
- default
- dot-syntax-swift3
- dot-syntax
- genstrings
- structured
- swift3
fonts:
custom:
bundled:
- default
- swift3
テンプレートは、Stencil(Mustache の Swift 版のようなもの)の形式で記述します。例えば次のような内容です。
enum {{enumName}}: String {
{% for image in images %}
case {{image|swiftIdentifier}} = "{{image}}"
{% endfor %}
}
より詳細は、Customize SwiftGen templates を参照してください。
Tips
Tips (1) : ビルド時に SwiftGen を実行する
リソース変更のたびに SwiftGen を実行するのは面倒で、忘れがちです。
そこで、Xcode の Build Phase で実行してしまう(ビルド時にコード自動生成もついでに行う)のが良いと思います。具体例が Integrate SwiftGen in an xcodeproj に書かれています。
Tips (2) : コマンドをプロジェクトに追加する
SwiftGen を使う場合は、通常は Homebrew などでインストールする必要があります。
しかし、CocoaPods で SwiftGen を追加すると、swiftgen
コマンドがプロジェクト内に追加されます(CocoaPods は一般にはライブラリを追加するツールですが、ここではライブラリは追加されずコマンドが追加されます)。Xcode の Build Phase で実行する場合に、コマンドが確実に存在するので便利です。
まとめ
- リソースからコードを自動生成してくれる
- リソース指定文字列のミスがなくなり、コードが書きやすくなる
- 生成コードは必要に応じてカスタマイズできる
- ビルド時に自動生成をしておくと便利
なお、この記事は、関モバ #17 で行った LT(SwiftGen // SpeakerDeck)をベースに作成しました。