Generates a simply structure from your assets (images and colors) and strings dynamically each time you build the project:
import UIKit
enum R {
enum Image {
static var `avatar`: UIImage { UIImage(named: "avatar")! }
static var `someImages_kickstarter2`: UIImage { UIImage(named: "some images/kickstarter-2")! }
static var all: [UIImage] {[
`avatar`,
`someImages_kickstarter2`,
]}
}
enum Color {
static var `accentColor`: UIColor { UIColor(named: "AccentColor")! }
static var `eightSomething`: UIColor { UIColor(named: "8something")! }
// ...
}
enum String {
/// Add to favorites action
static var `resourcesTest_addToFavorites`: Swift.String {
NSLocalizedString(
// also works for "resourcesTest_addToFavorites", "resources_test_add_to_favorites", etc
"ResourcesTest.addToFavorites",
tableName: "Localizable",
bundle: .main,
value: "Add to favorites",
comment: "Add to favorites action"
)
}
// ...
}
static var all: [Any] {
R.Image.all + R.Color.all + R.String.all
}
static func checkResources(shouldPrint: Bool = true) {
// ...
}
}Please follow all the following steps to know how it works and have all the necessary files set up.
- You need python 3 installed and you should have an alias/symbolic link to the binary with the name "python3".
- You will also need the
gyb.pyprogram made by Apple developers.- Official file link: https://github.com/apple/swift/blob/main/utils/gyb.py
- Some unofficial documentation and tutorials: https://nshipster.com/swift-gyb/
- Put
gyb.pyinside thegyb_resources_allfolder of the project, the structure should be:
├── LICENSE
├── README.md
├── gyb_resources_all # (folder) all files necessary for what we want
│ ├── __init__.py # necessay file to easily use gyb_resources.py
│ ├── generate_resources.sh # script to use in Xcode
│ ├── gyb.py # apple's gyb
│ ├── gyb_resources.py # python script to generate code
│ ├── gyb_resources_assets.py # python script to generate code
│ ├── gyb_resources_common.py # python script to generate code
│ ├── gyb_resources_strings.py # python script to generate code
│ └── gyb_script.py # look for each gyb file to run it with gyb.py
├── resourcesTest # project folder name
- Build and run the project.
Notes:
The file that will generate the structure for your assets is R.swift.gyb, you can customize it if you like.
The R.swift file should not be manually modified since it is automatically generated by R.swift.gyb.
- You can use the
Rstructure in your code like this:
imageView1.image = R.Image.avatarview1.backgroundColor = R.Color.accentColor- You need to copy the
gyb_resources_allfolder to the root folder of your project:
├── gyb_resources_all
│ ├── __init__.py
│ ├── generate_resources.sh
│ ├── gyb.py
│ ├── gyb_resources.py
│ ├── gyb_resources_assets.py
│ ├── gyb_resources_common.py
│ ├── gyb_resources_strings.py
│ └── gyb_script.py
- Change the variable
project_nameinsidegyb_script.pyto your project folder name. - Copy
R.swift.gybwhere you wantR.swiftto be generated.R.swift.gybshould NOT be added to your current target, so it should not be compiled (Compile sources) or copied to the app bundle resources (Copy bundle resources). - You must create a new
Run Script Phasein theBuild Phasestab and these are its settings: Shell:/bin/shScript content:
cd $PROJECT_DIR/gyb_resources_all
./generate_resources.shRun script: uncheck "for install builds only" and "based on dependendy analysis"
- IMPORTANT drag up this script build phase so that it appears BEFORE
Compile Sources. Example:
- Dependencies
- GYB # your script created in step 4, you can rename it
- Compile Sources
- ...
- Make sure that the
.stringsfile encoding matches the encoding specified ingyb_resources_all/gyb_resources_strings.py. To be sure convert your localizable strings file toUTF-8withiconv -f UTF-16LE -t UTF-8 Localizable.strings > Localizable2.stringsthen deleteLocalizable.stringsand renameLocalizable2.stringstoLocalizable.strings. Then make sure the encoding is set toUTF-8inside Xcode too.
Note: If you need to have UTF-16 strings just make sure the strings file is on that encoding and also change this line in gyb_resources_strings.py: with open(strings_path, encoding='utf-8') as f: replacing utf-8 for the desired encoding.
- You should be able to compile your project. After this a new file named
R.swiftshould be generated alongsideR.swift.gyb, dragR.swiftto the project adding it to the proper target/s.R.swiftshould be treated as any other swift file (it should be compiled) BUT you should not modify it manually, since that file will change depending on your assets.
- The file that will generate the structure for your assets is
R.swift.gyb, you can customize it if you like. - The
R.swiftfile should not be manually modified since it is automatically generated byR.swift.gyb. - Try not to use weird asset names (this is handled properly but just in case).
- Nested folders work BUT only if all nested folders use the same setting for "provides namespace".
- .strings files should have UTF-8 encoding, convert your Localizable.strings with
iconv -f UTF-16LE -t UTF-8 Localizable.strings > Localizable2.strings. If you need to useUTF-16change the encoder parameter in the filegyb_resources_strings.pyinwith open(strings_path, encoding='utf-8') as f:fromutf-8toutf-16or other. - The script respects the "provides namespace" option and works fine when you mark a folder with that option.
- If your
Assets.xcassetsis named differently or located in other folder different than the root folder, just modifyR.swift.gybadding the folder path in the function callsimage_resources("myAssets.xcassets")andcolor_resources("myAssets.xcassets"). You can do the same with the strings resources function. - You can use
R.checkResources()to verify all your assets at runtime. This is recommended to call when running your app in debug mode. IF YOU ENCOUNTER AN ERROR RUNNING IT, create an issue because maybe some assets weren't added properly.
- Generate strings from Localizable.strings
- Support multiline string (without \n) in strings file.
- Localizable string dictionaries.
- Support other file types, like maybe fonts or audio files located on a specific project folder.