In one of my previous articles, I mentioned how SPM (Swift Package Manager) changed the way I build and maintain my Code. I praised the deep integration Xcode 11 has with Swift Packages and how easy it is to create a tremendous modular Code.
But this “heaven” is not perfect; one thing was missing – The ability to add files to a Swift Package other than Code. You cannot add images, data files, or even a storyboard.
Fortunately, Apple made some changes in Swift 5.3 and Xcode 12.
Wait. Swift Package…remind me?
Swift Package is a reusable component of Swift, Obj-c, or C++ library that you can easily create and share among your projects. You can have it locally or fetch it from a dedicated git repository. Not only Swift Package can help you reuse your code, it also makes your project more modular and can help you manage your tests much better.
Now resources are also legitimate citizens
Equality for all! In Xcode 12, you can add resources to your packages. What types of resources? Basically, anything you need, from Images, Data Files, Storyboard, and even localization files.
Adding a resource is pretty straightforward – just right click on the package folder under the sources folder in your project navigator add select “New File”:
Note: Pay attention not to tap on the root of your package folder. You can only add Code or resources to the folder I mentioned above.
How can I access my resource from Code?
Ok, so we have some small adjustments we need to make here.
For example, let’s talk about images.
We can add an asset catalog to a package. Generally, to allocate an image based on the asset, we would do something like that:
let image = UIImage(named : “rightArrow”)
But inside a package that produces nil. That’s because our Code searches for the image inside the main bundle. We need to tell UIKit to search for the image inside our module bundle:
let image = UIImage(named: "rightArrow", in: .module, compatibleWith: nil)
As you can see, accessing resources from Code requires to mention the module bundle, otherwise, you’ll just get nil.
That’s it? I’m downloading Xcode 12!
Wait a second. What I mentioned above is relevant for files that are clear what is their purpose, like:
– Asset catalog
– .xib files
But there are files that we need to tell Xcode what to do with them – do we need those files in runtime, or it’s there only for development tasks?
For example, let’s say we have a documentation file we don’t want to be bundled with our package.
What we need to do here, is to update our package’s manifest file with this information:
.target(name: "MyNewPacakge", dependencies: , path: nil, exclude: ["notes.txt"]),
We can also add a full directory to be ignored. It is actually pretty similar to the “Compile Sources” mechanism we have under Target in Xcode.
If you do want your files to be treated as resources, add it to your resources part of your target in your packages’s manifest file:
.target(name: "MyNewPacakge", dependencies: , path: nil, exclude: ["notes.txt"], resources:[.process("myImage.png")]),
Ok, so how this changes the game?
Think of all the options opened up for you.
– A Core Data Persistent Layer – Core Data initialization process requires a data model, so creating a data layer was almost impossible. But now, adding an xcdatamodel file is a straightforward task. It’s especially crucial since data layers are a low-level layer and are mostly a dependency for higher packages.
– UI Components Package – UI Components sometimes contain images and rely on xib files. Now you can share your components within your projects.
– View Controllers – If you have a special files picker or a custom modal screen you want to reuse, now you can bundle it to a package since you have what it needs, whether it’s a storyboard or a xib file.
– Localization – Now that we can share view controllers, we need to localize them, right? lproj files can be easily added to packages with no time.
Apple is pushing Swift Packages to be your basic unit for your projects. It’s only natural for Swift Packages to contain resources as they become more and more popular. The integration of SPM with Xcode 12, and this new capability makes Swift Packages Manager a truly remarkable tool.