はじめに
本記事は Swift/Kotlin愛好会 Advent Calendar 2021 の14日目の記事です。
空いていたので埋めました。
Swift Package内のリソースにアクセスするには bundle:
に Bundle.main
でなく Bundle.module
を指定する必要があります。
毎回指定するのが手間なので、私は便利メソッドを実装し、さらに リソースへのアクセスを1つのSwiftファイルにまとめています 。
その方法を紹介します。
環境
- OS:macOS Big Sur 11.6
- Swift:5.5.2
- Xcode:13.2.1 (13C100)
リソースの格納
Swift Packageにおいて、リソースのほとんどは Sources/{target name}/Resources/
フォルダに格納すれば自動的にリソースと認識します。
リソースにアクセスする便利な方法
私は R.swift
というファイルを作成し、Androidに合わせて R.
で 静的にリソースへアクセスできる ようにしています。
アクセス修飾子は基本的に internal
(何も付けない)にしておき、 target外に公開するリソースのみpublic
にする のがいいと思います。
NSLocalizedString
Localizable.strings
からローカライズ文字列を取得します。
createNSLocalizedString(_:)
メソッドを用意して、簡単にローカライズ文字列を生成できるようにしています。
NSLocalizedString
の実態は String
なのに注意です。
ローカライズ文字列は static let
で静的に保持しています。
変数名はできる限りリソース名に合わせるとわかりやすい です。
enum R {
enum LocalizedString {
// MARK: Internal Stored Type Properties
// !!!: ここにローカライズ文字列へのアクセスを追加する
static let contactUs = nsLocalizedString("Contact us")
static let version = nsLocalizedString("Version")
// MARK: Other Private Type Methods
private static func nsLocalizedString(_ key: String) -> String {
NSLocalizedString(key, bundle: .module, comment: key)
}
}
}
呼び出し方は以下の通りです。
label.text = R.LocalizedString.contactUs
UIColor
*.xcassets
から UIColor
を取得します。
NSLocalizedString
とほぼ同様なので、詳細は省略します。
enum R {
enum Color {
// MARK: Internal Stored Type Properties
// !!!: ここに色へのアクセスを追加する
static let labelBackground = uiColor(named: "LabelBackground")
// MARK: Other Private Type Methods
private static func uiColor(named name: String) -> UIColor {
guard let color = UIColor(named: name, in: .module, compatibleWith: nil) else {
fatalError("Fail to load '\(name)' color.")
}
return color
}
}
}
呼び出し方は以下の通りです。
label.backgroundColor = R.Color.labelBackground
UIImage
*.xcassets
から UIImage
を取得します。
UIColor
とほぼ同様なので、詳細は省略します。
enum R {
enum Image {
// MARK: Internal Stored Type Properties
// !!!: ここに画像へのアクセスを追加する
static let uhooiIcon = uiImage(named: "Uhooi")
// MARK: Other Private Type Methods
private static func uiImage(named name: String) -> UIImage {
guard let image = UIImage(named: name, in: .module, with: nil) else {
fatalError("Fail to load '\(name)' image.")
}
return image
}
}
}
呼び出し方は以下の通りです。
imageView.image = R.Image.uhooiIcon
UIStoryboard
*.storyboard
から対象の UIViewController
を取得します。
私は UIStoryboard
を直接使うことがないので、 instantiateInitialViewController(_:)
メソッドを用意して対象の UIViewController
を取得するようにしています。
enum R {
enum Storyboard {
// MARK: Enums
// !!!: ここにストーリーボードへのアクセスを追加する
enum MonsterList {
static func instantiateInitialViewController() -> MonsterListViewController {
Storyboard.instantiateInitialViewController(named: "MonsterList")
}
}
enum MonsterDetail {
static func instantiateInitialViewController() -> MonsterDetailViewController {
Storyboard.instantiateInitialViewController(named: "MonsterDetail")
}
}
// MARK: Other Private Type Methods
private static func instantiateInitialViewController<T: UIViewController>(named name: String) -> T {
guard let vc = uiStoryboard(name: name).instantiateInitialViewController() as? T else {
fatalError("Fail to load \(T.self) from '\(name)' Storyboard.")
}
return vc
}
private static func uiStoryboard(name: String) -> UIStoryboard {
UIStoryboard(name: name, bundle: .module)
}
}
}
呼び出し方は以下の通りです。
let vc = R.Storyboard.MonsterList.instantiateInitialViewController()
UINib
*.xib
から UINib
を取得します。
他とほぼ同様なので、詳細は省略します。
enum R {
enum Nib {
// MARK: Internal Stored Type Properties
// !!!: ここにジブへのアクセスを追加する
static let monsterCollectionViewCell = uiNib(name: "MonsterCollectionViewCell")
// MARK: Other Private Type Methods
private static func uiNib(name: String) -> UINib {
UINib(nibName: name, bundle: .module)
}
}
}
呼び出し方は以下の通りです。
let monsterCellRegistration = UICollectionView.CellRegistration<MonsterCollectionViewCell, MonsterItem>(
cellNib: R.Nib.monsterCollectionViewCell) { cell, _, monster in
cell.setupWith(name: monster.name, iconUrl: monster.iconUrl, elevation: 1.0)
}
おわりに
これでSwift Package内のリソースへ簡単にアクセスできます
ただ手動で実装するのは手間なので、 ツールを使って自動で生成したい です。
R.swift ではできなさそうでした。
試したことないですが、 SwiftGen だとテンプレートを自作できるのでできそうです。
また、みなさんのSwift Package内のリソースへのアクセス方法も教えていただけると嬉しいです。
以上 Swift/Kotlin愛好会 Advent Calendar 2021 の14日目の記事でした。