SwiftPackageManagerでxibファイルを使う
この記事は、「愛好会 開発合宿in沖縄に参加してきた(成果編) SPMベースのプロジェクトを作る」の記事の解説記事の1つです。
この記事では、SPMでxibファイルを使う方法をまとめました。
現在筆者がUIを作る時は、①SwiftUI
or ②UIKit
を使用して全てコードで作るが、現状会社のアプリにはxib
やStoryboard
も含まれているので、今回はPackage
内でxib
などのInterfaceBuilder
(以下、IB)のファイルを使う方法をまとめます。
今回もSPMProjectのリポジトリをサンプルとして利用します。
xib
ファイルはResource扱いになる
まず確認しなければいけないのは、xib
などのファイルはResource
扱いになる、つまりBundle
ディレクトリに格納されるということです。
したがってそこの設定を間違えると、ただしくxib
ファイルがロードできないというトラブルが発生してしまいます。
この詳細は、WWDC2020のSwift packages: Resources and localization
の動画で説明されています。
上記の動画で説明があるように、Package
ではResources
ディレクトリにリソースファイルは含める必要がありますが、xib
やstoryboard
, xcassets
などファイルは自動でBundle
にコピーされるので、どこに配置しても問題はありません。
逆にjson
やscript
ファイルなど、他のファイルの場合はResources
ディレクトリに配置する必要があります。
xibファイルの実装方法
基本的な実装方法は同じですが、異なる点や注意点があるので、それらをまとめます。
ClassのModule
はPackage名にする
以下のxib
のFile's Owner
の設定で、デフォルトはInherit Module From Target
に✅が入っていると思います。
しかしそのままだとxib
がうまくロードできないので、✅を外して、Module
の名前をそのxib
が格納されているPackage
名に変更しましょう
コードからxibをロードする時は、Bundle.module
のBundle
を指定する
実際にコードからxib
をロードする時には、Bundle
を指定すると思いますが、その時に例えばBundle.main
を指定しまうと、アプリのメインのTarget
のBundle
が指定されてしまい、格納されているBundle
が異なるので、うまくロードできません。
そこでPackage
でBundle
を指定する場合は、Bundle.module
を指定します。
このアプリではxib
をロードするようのコードを以下のように共通化しています。
public extension UIView {
func loadNib(bundle: Bundle? = nil) {
let nib = UINib(nibName: String(describing: type(of: self)), bundle: bundle ?? Bundle(for: type(of: self)))
guard let view = nib.instantiate(withOwner: self, options: nil).first as? UIView else { return }
addSubview(view)
view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
view.topAnchor.constraint(equalTo: topAnchor),
view.leadingAnchor.constraint(equalTo: leadingAnchor),
trailingAnchor.constraint(equalTo: view.trailingAnchor),
bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
}
この関数は引数にBundle
を指定するようになっているので、使用する時に以下のように、.module
を指定します
loadNib(bundle: .module)
xib
で画像を使用する時の注意点
今までマルチモジュール構成をする時は、1つのモジュールに画像などを集約するようにしていたが、xib
の場合は他のモジュール(Bundle
)の画像を表示することができません。
正確にはIB
上では画像は選択することができて、表示もされるのですが、実際にアプリをビルドしてみると、その画像は表示されません。IBOutlet
で接続後に、コードで設定することもできますが、それではxib
などのIB
を使うメリットが半減です。
これでは運用的にも微妙なので、別の解説記事に書いた通り、画像についてはPackage
ごとに管理するのが現時点ではよさそうです
ちなみにアセットの色はファイルは共通のPackage
のものを利用することができます。