まだハードコードで消耗してるの?
iOSアプリ開発で_Storyboard_,_Xib_を使用してUI部分を作成している人は多いのではないでしょうか?
時には_Storyboard_や_Xib_からインスタンスを作成してごにょりたい場面もあると思います。
プロジェクト内のリソースを使用する場合、通常はリソースの名前を文字列でハードコードする必要があります。
// Get ViewController
let storyboard = UIStoryboard(name: "Storyboard", bundle: nil)
let viewController = storyboard.instantiateViewControllerWithIdentifier("XXXX") as! ViewController
// PerformSegue
performSegueWithIdentifier("Open", sender: sender)
// Nib
let nib = UINib(nibName: "TableViewCell", bundle: nil)
let cell = nib.instantiateWithOwner(nil, options: nil)[0] as! TableViewCell
この文字列でリソースを取得する方法には問題が生まれます。(詳しくは後述します。)
そんな問題を解決してくれるライブラリResourceKitを作りました。
ResourceKitで実現できること
ResourceKitはXcodeの_Run script_の使用を前提にしたライブラリです。
ResourceKitは文字列でリソースを使用する機能をメソッドやプロパティに変換して自動で作成してくれます。
先ほどのコードをResourceKitを使用するこうなります。
// Get ViewController
let viewController = ViewController.instanceFromStoryboard()
// PerformSegue
performSegueOpen()
// Nib
let cell = TableViewCell.Xib().view()
これで同じ意味になります。
自動生成されたResourceKit.generated.swift
でメソッドやプロパティとして提供してます。
これにより補完が有効になりコーディングがはかどります。
捗った分だけテトリスができます。(やったね)
文字列をハードコードする問題点
思いつく限り箇条書きします。
- 補完が効かない → テトリスする時間が減る。
- リソースごと消してした場合、使用している場所を探して(grepして)、削除する。削除し忘れていたらクラッシュする → テトリスタイムが減る。
- リソースの名前を変更した場合、使用している場所を探して(grepして)、新しいリソース名にして、変えた場所をテストして、typoしてたらクラッシュする → テトる時間が減る。
- 文字列のハードコードでリソースを取得するメソッドは本当にその名前で存在するかわからないから、Optionalになっており、外すコードを書く必要がある → テトリス...
- そもそもコンパイラがチェックできない領域にいるのでクラッシュやバグの危険性は常にはらんでいる。 → Oh my tetris!!
一番問題だと思ったのは5番です。
人間がチェックする領域じゃないな、と思い
コンパイラがチェックできる領域のものへと変えてしまおうと思い作成しました。
ResourceKitを使用すればコンパイル時にエラーを出してくれるので漏れが出にくいはずです。
ResourceKitを導入
https://github.com/bannzai/ResourceKit#installation
README 参考。
R.swift
というライブラリと導入の仕方が酷似しているためそちらを参考にしてもいいかもしれません。
他にも機能があるので使い方は[Examples]
(https://github.com/bannzai/ResourceKit/tree/master/Documents)か**ResourceKitDemo**を確認してください。
ResourceKitを作るまでの過程
R.swiftというライブラリがあります。
ResourceKitはR.swiftにインスパイアされて作りました。
こちらのライブラリは導入の仕方や実現したいことはResourceKitと同じだと考えています。サポートされている範囲はR.swiftの方が広いです。
ResourceKit開発のきっかけは現在業務で携わっているiOSアプリで「R.swift導入しようぜ!」という話が挙がりました。
ただ、導入する上で幾つか問題点がありました。
- 多機能すぎる。
- 多機能がためにGenerateの時間が長い。
- Objective-CからR.swiftの機能が使えない
- Generate対象にCocoapodsで導入したThird party製のUIライブラリが含まれているとコンパイルエラーになり使えない。
等があげられたので、
現在のプロジェクトに導入するのは厳しいのではないかと考えられ
そこで欲しいものは作ってしまおうという精神で作りました。
ResourceKitで実現したかったこと、されていること
- コンテキストにクラス名が記述されている。
- 可読性、書きやすさ、定義ジャンプしやすさを実現している。
-
performSegue
に文字列を使用しなくていい。 - クラスのextensionなっているので、Objective-Cで使用できる。(一部利用できない)
- クラスのextensionなっているので、
ResouceKit.generated.swift
Xcodeで検索しやすい。(Ctrl + 6) - UIColorやUIFontまでサポートされているがそこまではいらない。
- Third party 製のUIライブラリでも使える。
ResouceKit.generated.swift
にimport XXXX
を書けば使用できます。これは上書きされません。
ResourceKitを使う上での制約
- UIColorやUIFontはサポートするか未定。
- サポートするUIViewControllerに制約がある。
- クラス名のSuffix が
ViewController
のクラスのみ機能をGenerateする。 - 多言語化されたstoryboardはGenerate対象になっていない。(需要によって作る)
最後に
個人的にはハードコードを避けられる規約を決めて開発を進める方法を取れればそれでいいと考えています。 ですが、プロジェクトに途中からジョインされた場合等なかなかそれが実現できない理由もあります。
もし同じような局面やこれからの導入と思っている人はResourceKitの導入も考えてみてください。現状での改善点や機能追加案をissue,pull-reqをもらえたら嬉しいです。(日本語でおkです)
ResourceKitはまだ対応すべきことがあるライブラリです。
これから対応していこうと考えているリストです。
- UIImage support.
- NSLocalizedString support.
- サポートする内容が増えてもGenerateする項目を選択できるようにする。
- Generate時間の継続的チューニング
サポートする内容が増えてもGenerateする項目を選択できるようにする。
これはプロジェクトごとによって求められるものが違うと考えるからです。
不必要なものまでGenerateして余分な時間がかからないようにしようと考えています。
issue,pull-req,ご意見、ご要望、テトリス勝負お待ちしてます\(^o^)/