A brief intro to Swift packages

Nicolas Savoini
Mac O’Clock
Published in
5 min readMay 18, 2020
Photo by Guillaume Bolduc on Unsplash

Over the past month, I’ve been working on a new iOS App. I got the idea a long time ago but never really start coding it. This is mostly because I’m not good with Swift storyboard (the way to design the user interface). Last year Apple unveiled SwiftUI, and with it, an easy way to create such interface. Combine that with the world nowadays (being stuck at home) and you’ve got an app in the making.

The Situation

In the application, I keep track of places like restaurants, bars, hotels… Each of them has a location, an address. An address is usually in a country.

Thanks to Apple, all the countries are already in the operating system. There is no need to add a JSON file, or do a lot of data entry. You just need to call the right method.

For each place, I want to record the address. The address will have the country. For each country, I want to have its code, its name, and its flag.

The code by itself is not difficult. To have the list of all the countries with code, name and flag, you need a new Struct. The country code will be given by Swift framework, the name will also be retrieved via Swift, and the flag will be calculated, thanks to a nice method found on StackOverFlow;)

public struct Country: Hashable {
public var code: String
public var name: String {...}
public var flag: String {...}
public var flagAndName: String {...)
}

You quickly get your structure but then you need all the convenience methods to use it.

  • A Global Variable with all countries as the Struct showed above
  • A way to create a Country from a String representing the code
  • A way to create a Country from a String representing the name
  • A way to extract all possibles Countries from an Array of String

Don’t ask about the last one but I do need it;)

Once again the code is not difficult, you have a global variable, an enum and 2 extensions. But you will probably need it in a bunch of applications. After all a lot of programs out there need to deal with countries…

The Solution

The solution is to create a Swift Package.

A Swift Package is a library, or a small piece of code you can use over and over. Ideally it is well documented and also well tested, so that when you use it, you don’t have to spend time on bugs and stuff…

The first added benefit of using a Swift Package is the compilation time of your project. If you have the code directly in your project, it will be recompiled every time. Having it in the library means there is no need for that.

The second added benefit is you get all improvements in your project for free. If you update the package, all your applications using the package will be updated. You do not have to go back to any project and copy-past code…

Let’s do it

First we need to create a new package within Xcode.

Open Xcode
File > New
Swift Package

Give it the name you want, then click on Create.

Xcode will display the package configuration file. You can find the name of your package and different information like the dependencies needed, the compatible platforms, and the targets. As this is a pretty simple package, we will leave it as is.

Under the Source folder, you should see a Swift file with the same name as your package. The code goes here.

Pitfall:

In a package, everything you want to access from outside the package needs to be public!

The Global Variable

public enum CountryLibrary {
public static let countries: [Country] = ...
}

The Enum

public enum CountryIdentifier {
case code
case name
}

The extension

extension String {
public func country(by cIdentifier: CountryIdentifier) -> Country? {...}
}
extension Array where Element == String {
public func countries(by cIdentifier: CountryIdentifier) -> [Country] {...}
}

If you look at the Struct Country, you see that there is no defined constructor. In the package you can use the default constructor, same as usual. But because it is not made explicitly public, you will not be able to use it outside of the package.

Make sure you do a bunch of tests as well, so you do not share any nasty bugs. A good technique is TTD.

The deployment

Now that we got the package, you need to deploy it on Github.

First you need to activate Source Control for your project.

in Xcode
Click on Source Control
Click Create Git repositories

This will create a repository on your computer. Then you need to add a remote repository on GitHub.

In Xcode
In your project
Click on the second icon
Then go to Remote folder
Right Click
Create .. Remote

The icon for the Source Control management in Xcode.

PitFall:

You need to have a GitHub account… obviously. Those are free and quite easy to do, so it shouldn’t be an issue.

Pitfall:

When you add a Swift Package to a project, you have 3 options:

  • By Version
  • By Branch
  • By Commit

If you want people to use a specific version of your package, you need to define some. This can be done directly on GitHub website. You need to go to your project, then release.

This is not mandatory — you can use your package on the master branch. But if people want to use a specific version, or make sure the next update will not break anything, it is highly recommended to use a version number.

The end

You get a nice package, and you import it into your project.

Last tip: to use it, make sure you import it at the top of your file.

Full code: here.

Full final app: here

No more excuses to not split your code into very small and reusable pieces. ;)

--

--

Nicolas Savoini
Mac O’Clock

Passionate geek, I have few apps on the AppleStore and a lot of ideas:) write about Tech and Life. nicolas.savoini@mac.com