10 awesome Swift features for you diehard Swift naysayers

After being a die-hard Swift holdout (and fervent Objective-C defender), I dove head first into my first Swift-only project several months ago. The project was fairly new with only a few thousand lines of code, so it was the perfect opportunity to finally give Swift the honest chance it deserves.

I had many non-reconcilable issues with Swift's initial release syntax and tooling. It was simply too rough and unfinished. In recent months, however, notably with the 2.x line of releases, Swift has sincerely grown up and can finally be considered a "real" programming language. If you're still stubbornly on the Objective-C side of the fence - I get it - but consider this: Objective-C is over 30 years old; ancient by anyone's standards. And for all of Swift's kinks, it's as clean a break from the past as is possible for the Apple platform. Recent incarnations of the language drop all of Objective-C's antiquated C heritage and expresses itself through a clear, safe and reasonably terse syntax.

But why fix what ain't broke?

This is a legitimate question and there's no need to demonize Objective-C's dynamism. It has served developers well for over thirty years. So why has it been villainized of late? Clearly, there should still be a place in this world for dynamic languages like Objective-C. On the other hand, a whole class of bugs can be avoided by foregoing dynamism, while enabling compiler optimizations previously deemed impossible. Also, the dynamism/strictness debate seems to be seasonal, alternating from one to the other from time to time. I have come around and I'm now firmly pro-type safety. Inspired by functional programming, Swift also strongly encourages immutability, which in my opinion, leads to code which is easier to write and understand.

In the end, it's up to you to decide whether Swift can replace Objective-C in your app development toolbox. One thing is clear though: Apple has ceased improving Objective-C for its own sake. Instead, improvements are merely applied to serve better interoperability with Swift (like, recently, nullability and lightweight generics). All of Apple's future development efforts will be focused on Swift. It's not a bad idea to follow their lead, and now may not be such a bad time to start if you haven't already, as Apple has promised less code breakage in the post-Swift 3 timeframe.

Here are 10 Swift perks you can't take advantage of if you decide to stick with Objective-C:

  1. Default implementation with protocol extensions
  2. Easy early returns with guard let
  3. More fluent APIs with trailing closures
  4. Order-independent function parameters with default values (update)
  5. Single-line closure declaration by using order-based parameter names
  6. Easy namespacing with structs enums (update)
  7. Protocol implementation in extensions
  8. Defining multiple classes / structs / protocols / extensions in a single .swift file
  9. Auto-generated init parameters in structs
  10. Built-in support for lazy instance variables

I only have time for the first three today, so let's get to it.


1. Default implementation with protocol extensions

Protocols ("interfaces" in other languages) are "insanely great". They're one of the building blocks of software architecture and have a place in every software project. Swift's protocols are even more powerful when they are combined with extensions. They are effectively what Rubyists call mixins: bits of behavior that can be added to classes without the need for subclassing. The following example was taken from my open source toolkit for the Coordinator design pattern, called CoordinatorKit.

Consider the Coordinator and ComposableCoordinator protocols:

public protocol Coordinator: class {
    func start()
}

public protocol ComposableCoordinator: Coordinator {
    var childCoordinators: [Coordinator] { get set }
}

They simply define that any Coordinator should at least have a start() method and that any Coordinator that fits into a hierarchy of coordinators should at least expose an array of its children.

A common operation in this model would be to look up a child coordinator by its type, and return it. The following method accomplishes this recurring bit of functionality:

func findChildCoordinator<T>(type: T.Type) -> T?

To avoid having to re-implement this all over the place (or having to define it as a public function), one way to go about it would be to create an abstract superclass which implements ComposableCoordinator and implement it there. While is works, it's a bit of a code smell, because Swift has no official notion of 'abstract' classes. This enforced subclassing is also limiting to the user, because like most object-oriented programming languages, Swift only allows single inheritance. The Swift-way would be to declare this recurring functionality in a protocol extension:

extension ComposableCoordinator {
    public func findChildCoordinator<T>(type: T.Type) -> T? {
        return childCoordinators.filter({ (coordinator) -> Bool in
            return coordinator is T
        }).first as? T
    }
}

Any class which conforms to ComposableCoordinator will get the findChildCoordinator<T>() method for free, without the need for subclassing. Because this is protocol-oriented, you can mix in any amount of functionality, in a way that doesn't rely on convention and is supported by the language and tooling. Xcode will autocomplete this method signature on any compliant class, provided SourceKit isn't crashing, of course (wink wink).

2. Easy early returns with guard let

The handling of optionals is very prominent in Swift because it's one of the ways the language guarantees safety. Objective-C, in contrast, provides no safeguards around the handling of nil values, potentially leading to various types of nil-related crashes. While being so explicit about optional values increases safety, it adds programmer overhead in the form of countless optional unwrapping if let statements. Thankfully, Apple resolved the if let-nesting issue with the introduction of compound if let statements, but what is this guard let thing then?

Oftentimes, multiple optional values need to be unwrapped as a means of validation before proceeding execution of a method. To prevent many repetitions of if let (nested or not), you can employ guard let at the beginning of a scope to unwrap optionals and force an early return (and additionally throw an error or do some other kind of handling). After this point, you can simply pretend optionals don't exist.

Consider this contrived example for some hypothetical sign-in code:

func login(usernameText:String?, passwordText:String?, captchaText:String?, completion:(error:NSError?)->()) {
    // Catch empty values and call closure with an error
    guard let username = usernameText, password = passwordText, captcha = captchaText
    else {
        let error = // some error
        completion(error: error)
        return
    }

    // regular login handling continues here
}

Optional unwrapping is conveniently focused in one place, without the need for nesting or logic branching.

3. More fluent APIs with trailing closures

Since the introduction of Objective-C blocks ("closures" in Swift), Apple has been adding them to its APIs wherever it makes sense. Completion closures are by far the most common. For example:

UIView.animateWithDuration(1, animations: {
    // Animation code
})

With Swift, whenever a closure is the last parameter, you can use this more compact notation:

UIView.animationWithDuration(1) {
    // Animation code
}

Superficial, I know, but it turns closures into first-class citizens. They fit in more naturally with the rest of the language and reduce visual clutter by eliminating the closing parentheses.


Attribution

Header image courtesy of Tristan Ferne on Flickr (CC BY 2.0).

Updates

I would like to thank the following people for responding constructively to my write-up:

On reorderable parameters: Kyro38 on /r/swift correctly pointed out that this feature has actually been removed in Swift 3.. I guess it was nice while it lasted. You can find the Swift Evolution Proposal here. If you've been using this feature (like me), it won't hurt to prepare your code for this upcoming change.

On using structs for namespacing: @boolkybear suggested on Twitter that using enums would be better because they can't be instantiated, contrary to structs. True that!

Stubbing network requests with fixtures

Developing client and server networking code in lockstep with OHHTTPStubs fixtures. This Swift/Obj-C library provides an easy way to hook into the iOS HTTP networking stack to serve local responses for offline integration and unit testing.


You'd be hard-pressed to find an iOS project that doesn't contain networking code. Saving user data, requesting app content and storing away analytics are just a selection of the activities that require network access.

Developing against the live API is clearly the most desirable, but what if it's still being developed in parallel? Or down for some reason?

Until recently, I would create an alternative implementation and manually stub out the expected API behavior in code. I'd write my unit tests and also inject the stubbed interface into the actual application so I could get ahead with the UI. This approach is uncomplicated and works reasonably well.

Where it breaks down for me is its manual nature. With each revision of the API interface, the stub needs to follow along. And as the stub's implementation expands, this repetitive process grows all the more cumbersome.


OHHTTPStubs' roots lie in Objective-C, but it is perfectly Swift-compatible. When enabled, HTTP responses are intercepted and replaced with predefined fixtures. These typically contain sample output for API calls in JSON, though they can be supplied in any text format.

I have created a basic demo project to demonstrate how this library could be used in your next project. It's all up on GitHub, so feel free to clone/fork it and follow along.


It's an iPhone app which uses Alamofire to call the /ip endpoint of HTTPBin.org. A tap on either button will call the web service and display the response in a UIAlertController.

Here's the implementation for getIPAddress() (AddressHTTPService.swift, line 14):

func getIPAddress(callback: (String) -> ()) {
    Alamofire.request(.GET, "https://httpbin.org/ip").responseJSON { response in
        if let JSON = response.result.value, origin = JSON["origin"] {
            callback(origin as! String)
        }
    }
}

In the same file, I defined a separate class to hold the logic for loading and unloading the fixtures. You're free to choose where you put this code, as it doesn't particularly matter. Wrapping it in a separate class is also optional.

class AddressHTTPServiceStubs {
    static func loadStubs() {
        stub(isPath("/ip")) { request in
            let stubPath = OHPathForFile("ip_response.json", AddressHTTPService.self)
            return fixture(stubPath!, headers: ["Content-Type":"application/json"])
        }
        OHHTTPStubs.setEnabled(true)
    }

    static func unloadStubs() {
        OHHTTPStubs.setEnabled(false)
    }
}

To enable the stubs in your application or tests, simply call the loadStubs() method:

@IBAction func getIpViaStub(sender: UIButton) {
    AddressHTTPServiceStubs.loadStubs()
    self.showIPAddress()
}

The library comes with a couple of built-in request matchers. However, the raw request object is accessible, so more granular filtering shouldn't be too challenging.

That's it!


As you can see it's fairly easy to put stubbed responses in place for offline or unit testing. It's mostly a matter of writing a filter to direct OHHTTPStubs to the correct fixture file, and updating the canned responses whenever an associated API changes.

Credits

Feature image courtesy of Radomir Cernoch, who generously licensed this photo as Attribution-ShareAlike 2.0 Generic. Thank you!