How To Use Namespaces In Swift

How To Use Namespaces In Swift

Swift modules makes the need for class prefixes obsolete. In Objective-C, it is a best practice to use a class prefix to avoid naming collisions with other libraries and frameworks, including Apple's.

Even though modules an important step forward, they are not as flexible as many of us would want them to be. Swift currently doesn't offer a solution to namespace types and constants within modules.

A very common problem I run into when working with Swift is defining constants in such a way that they are easy to understand by anyone working on the project. In Objective-C, this would look something like this.

NSString * const CCAPIBaseURL = @"https://example.com/v1";
NSString * const CCAPIToken = @"sdfiug8186qf68qsdf18389qsh4niuy1";

This works fine, but it isn't pretty and easy to read. Even though Swift doesn't support namespaces within modules, there are several viable solutions to this problem. The option I commonly adopt in Swift projects uses structures to create namespaces. The solution looks something like this.

struct API {

    static let BaseURL = "https://example.com/v1/"
    static let Token = "sdfiug8186qf68qsdf18389qsh4niuy1"

}

I believe this neat trick was first coined by Jesse Squires. It works great and I love the syntax to access the constants.

if let URL = NSURL(string: API.BaseURL) {
    ...
}

There is one unwanted side effect. The API structure in the previous examples can be instantiated. While this isn't a problem in itself, it may lead to confusion among fellow developers.

You could make the initializer of the API structure private, making it inaccessible to other parts of the project. Note that this only works if the API structure lives in its own file. That is the result of how access control works in Swift.

struct API {

    private init() {}

    static let BaseURL = "https://example.com/v1/"
    static let Token = "sdfiug8186qf68qsdf18389qsh4niuy1"

}

Initializing a Structure Without Accessible Initializers

Using Enumerations

Another solution was proposed by Joseph Lord in a discussion on Twitter and written about by Natasha Murashev. Instead of using structures, Joseph proposes to use enumerations without cases. The result is that the enumeration, acting as a namespace, cannot be instantiated.

enum API {

    static let BaseURL = "https://example.com/v1/"
    static let Token = "sdfiug8186qf68qsdf18389qsh4niuy1"

}

Using this solution is almost identical to using structures. The main difference is the advantage highlighted by Joseph Lord, you cannot create an instance of the API enum without having an error thrown at you.

Initializing an Enumeration Without Cases

The above solution, using structs or enums, works very well for me and it is one of my favorite features about Swift. You don't have to put the constants of your project in one struct or enum. Take a look at the following more advanced example. You have to admit that his look very appealing, especially when compared to Objective-C.

enum API {

    static let BaseURL = "https://example.com/v1/"
    static let Token = "sdfiug8186qf68qsdf18389qsh4niuy1"

}

enum UserDefaults {

    static let CurrentVersion = "currentVesion"
    static let DarkModeEnabled = "darkModeEnabled"

}

enum Notifications {

    static let DidUpdateProfile = "DidUpdateProfile"
    static let DidUpdateReadState = "DidUpdateReadState"
    static let DidSynchronizeBookmarks = "DidSynchronizeBookmarks"

}
// Post Notification
let notificationCenter = NSNotificationCenter.defaultCenter()
notificationCenter.postNotificationName(Notifications.DidSynchronizeBookmarks, object: self)

// Update User Defaults
let userDefaults = NSUserDefaults.standardUserDefaults()
userDefaults.setBool(darkModeEnabled, forKey: UserDefaults.DarkModeEnabled)

How are you solving the problem of namespacing in Swift? Or do you stick with the approach many of use used in Objective-C? Let me know if the comments below or reach out to me on Twitter.