A common frustration with the iOS platform is that resources are accessed using magic strings. In practice, this means you'll find out if an image, icon, localized string etc. exists at runtime. Either by seeing what you were hoping for or getting a hard crash. Let's fix this by introducing your new best friend - R.swift.
Manage Your iOS Resources Type-Safely with R.swift
Written by
The developers behind the iOS platform should take a close look at how Android is handling resources (localized strings, images, icons, etc.). No resource references using magic strings - everything is statically typed as it should be. But don't worry - the iOS community comes to the rescue by providing a library for this missing feature in the platform.
In this post, we will uncover the tool R.swift that allows for accessing resources in a clean and type-safe way - and how you incorporate this tool in your iOS projects.
Why should you use R.swift?
R.swift provides strong typed, autocompleted resources like images, fonts and segues in Swift projects.
Let us look at an example to help paint the picture:
// Traditional way of accessing assets using strings // Consider what should happen if the image isn't there at runtime lazy var unsafeBackgroundImage: UIImageView = { guard let image = UIImage(named: "matteo-catanese.jpg") else { fatalError("Ouch, it wasn't there.") } let imageView = UIImageView(image: image) imageView.frame = containerView.frame return imageView }() // New way of accessing assets using R.swift // You'll get an error at compile-time if the image isn't there lazy var safeBackgroundImage: UIImageView = { let imageView = UIImageView(image: R.image.matteoCatanese()) imageView.frame = containerView.frame return imageView }()
Not only will you get an error compile-time, if you're referencing incorrect resources, but you will have autocompletion, so you never again have to guess the exact name of that icon, font, etc.
The way R.swift works is by scanning the project for resources during a build phase. It then generates an R.generated.swift
file containing one struct per resource type (R.image, R.font, R.string and so on) with properties for each specific resource in the project.
R.swift currently supports the following resources: images, custom fonts, resource files, reusable cells, localized strings, storyboards, segues, and nibs.
Setting up R.swift using Mint
My preferred way of setting up R.swift in a project is by using Mint. Mint is great for most CLI packages that you would normally download with Homebrew, as you can easily download and run a specific version of a package. This way, we can easily align each team member's development environment and reduce those annoying "it works on my machine"-issues.
First off, install Mint with Homebrew (as ironic that may be) by running brew install mint
in your terminal. Then you want to add a so-called Mintfile
in the root of your project. It should contain one line:
https://github.com/mac-cain13/R.swift.git@v5.1.0
Normally, you would add a library by using a format like mac-cain13/R.swift@5.1.0
but support for Mint was added recently and seems to still have some early quirks. The line above will do the job for now.
You'll then need to run mint bootstrap
in the root of your project to install R.swift. Now, open the project and add the package R.swift.Library
to your project via Swift Package Manager. This package will provide types to support the R.swift code generation in your project.
Once that's installed, you need to run the R.swift tool from a build phase, so that new resources become available with R.swift after each build. Go to the target of your app, select Build Phases
and create a new phase just above Compile Sources
. Paste the following script to be run by the build phase:
if mint list | grep -q 'R.swift'; then mint run R.swift rswift generate "$SRCROOT/YourProjectName/Resources/R.generated.swift" else echo "error: R.swift not installed; run 'mint bootstrap' to install" return -1 fi
Next, you want to add this line to the Input Files
:
$TEMP_DIR/rswift-lastrun
And this line to the Output Files
(assuming you want the R.generated.swift
in a Resources folder).
$SRCROOT/YourProjectName/Resources/R.generated.swift
The build phase should look like this:
Finally, create a Resources group in your project. Build your project, and in Finder, you will now see an R.generated.swift
in the root folder.
Go ahead and drag the R.generated.swift
file into your project and uncheck Copy items if needed
. You should end up with a folder structure similar to this:
Optional: Add *.generated.swift
to your .gitignore file to prevent merge conflicts.
We're done! Now, you should have autocompletion by using R.swift in your codebase.
Alternatives
There are various alternatives to R.swift. The most prominent one is SwiftGen, but the main reason that I use R.swift is that it inspects the Xcodeproj file for resources instead of asking you for files to use. That makes my part of the process a bit easier.
It also seems that R.swift is more actively maintained at the moment. The result is fairly similar, and if you're currently using SwiftGen or another alternative that gets the job done, you might as well stick to that.
Conclusion
That's it! We covered how you get started with R.swift in your iOS projects to achieve:
- Compile-time validation - no more incorrect strings that will crash your app at runtime
- Free autocompletion - never have to guess an asset name again
Thanks for reading. See you in another article!
Share this post
Facebook
Twitter
LinkedIn
Reddit
You may also like
Automation
iOS Continuous Deployment Using Travis CI and Fastlane
Continuous Deployment (CD) is a practice of using automation to release your code in a quick and sustainable way. Here’s how you set up CD for iOS apps to perform automated building, code signing and deployment to the App Store.
Swift
Start Your RxSwift Journey in Less Than 10 Minutes
RxSwift is well known for having a steep learning curve. But taking the time to learn it can easily be the next significant leap in your development abilities. We’ll cover the basic concepts of the library to quickly get you up to speed.
Automation
iOS Continuous Integration Using Travis CI and Fastlane
Continuous Integration (CI) is a powerful practice to keep any app in a stable state throughout its development. Here’s how you set up CI for iOS apps to automatically perform code validation and testing whenever your code changes.