iOS

SwiftPackageManagerでxibファイルを使う

SwiftPackageManagerでxibファイルを使う

この記事は、「愛好会 開発合宿in沖縄に参加してきた(成果編) SPMベースのプロジェクトを作る」の記事の解説記事の1つです。

愛好会 開発合宿in沖縄に参加してきた(成果編) SPMベースのプロジェクトを作る愛好会の開発合宿in沖縄に参加してきたので、その成果をまとめました! SwiftのSPMベースのプロジェクトのフィジビリ検証をしました!...

この記事では、SPMでxibファイルを使う方法をまとめました。

現在筆者がUIを作る時は、①SwiftUI or ②UIKitを使用して全てコードで作るが、現状会社のアプリにはxibStoryboardも含まれているので、今回はPackage内でxibなどのInterfaceBuilder(以下、IB)のファイルを使う方法をまとめます。

今回もSPMProjectのリポジトリをサンプルとして利用します。

xibファイルはResource扱いになる

まず確認しなければいけないのは、xibなどのファイルはResource扱いになる、つまりBundleディレクトリに格納されるということです。
したがってそこの設定を間違えると、ただしくxibファイルがロードできないというトラブルが発生してしまいます。
この詳細は、WWDC2020のSwift packages: Resources and localizationの動画で説明されています。

上記の動画で説明があるように、PackageではResourcesディレクトリにリソースファイルは含める必要がありますが、xibstoryboard, xcassetsなどファイルは自動でBundleにコピーされるので、どこに配置しても問題はありません。
逆にjsonscriptファイルなど、他のファイルの場合はResourcesディレクトリに配置する必要があります。

xibファイルの実装方法

基本的な実装方法は同じですが、異なる点や注意点があるので、それらをまとめます。

ClassのModuleはPackage名にする

以下のxibFile's Ownerの設定で、デフォルトはInherit Module From Targetに✅が入っていると思います。
しかしそのままだとxibがうまくロードできないので、✅を外して、Moduleの名前をそのxibが格納されているPackage名に変更しましょう

コードからxibをロードする時は、Bundle.moduleBundleを指定する

実際にコードからxibをロードする時には、Bundleを指定すると思いますが、その時に例えばBundle.mainを指定しまうと、アプリのメインのTargetBundleが指定されてしまい、格納されているBundleが異なるので、うまくロードできません。

そこでPackageBundleを指定する場合は、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のものを利用することができます。

SwiftGenとSwiftLintをSPMのプラグインで実行するSwiftGenとSwiftLintをSPMのプラグインで実行する方法をまとめました!...

参考資料

+2

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA