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.py
program 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.py
inside thegyb_resources_all
folder 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
R
structure in your code like this:
imageView1.image = R.Image.avatar
view1.backgroundColor = R.Color.accentColor
- You need to copy the
gyb_resources_all
folder 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_name
insidegyb_script.py
to your project folder name. - Copy
R.swift.gyb
where you wantR.swift
to be generated.R.swift.gyb
should 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 Phase
in theBuild Phases
tab and these are its settings: Shell:/bin/sh
Script content:
cd $PROJECT_DIR/gyb_resources_all
./generate_resources.sh
Run 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
.strings
file encoding matches the encoding specified ingyb_resources_all/gyb_resources_strings.py
. To be sure convert your localizable strings file toUTF-8
withiconv -f UTF-16LE -t UTF-8 Localizable.strings > Localizable2.strings
then deleteLocalizable.strings
and renameLocalizable2.strings
toLocalizable.strings
. Then make sure the encoding is set toUTF-8
inside 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.swift
should be generated alongsideR.swift.gyb
, dragR.swift
to the project adding it to the proper target/s.R.swift
should 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.swift
file 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-16
change the encoder parameter in the filegyb_resources_strings.py
inwith open(strings_path, encoding='utf-8') as f:
fromutf-8
toutf-16
or other. - The script respects the "provides namespace" option and works fine when you mark a folder with that option.
- If your
Assets.xcassets
is named differently or located in other folder different than the root folder, just modifyR.swift.gyb
adding 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.