Using didSet to configure IBOutlet views…

Swift’s didSet property observer is a great way to configure views linked via IBOutlet. It allows you to set properties that need to be dynamic at runtime or that can’t be configured via Interface Builder:

[gist https://gist.github.com/JoshuaSullivan/80e8d53505dbe2f0868f file=”DidSetExample.swift”]

However, it’s worth keeping a simple rule in mind when you go about configuring your views with didSet:

Don’t reference other IBOutlet views or implicitly unwrapped properties in your didSet block.

The reason for this is simple: you have no way of knowing which order your IBOutlets will be set in, so the other view or property you’re trying to access may not be there. At best, you’re going to be nil-checking a lot and end up only partially configuring your views, requiring follow-up elsewhere in code. At worst, you’re going to accidentally force-unwrap a nil and crash your app.

It’s okay to reference external objects, as seen in the call to the StyleManager above, as long as they’re non-optional and not subject to race conditions. The proper place to establish things like view layout relationships or properties from one view that copy the properties from another is still in viewDidLoad.

Avoid [unowned self] whenever possible!

One of the confusing aspects of Swift is how capture semantics work with closures. When used improperly, they can result in retain cycles or crash the app with the dreaded EXC_BAD_ACCESS. It is worth keeping in mind that capture semantics only apply to reference-based objects (classes); value objects can be used freely without worrying about this. The situation I’ll be looking at here is the capture of self, which is far-and-away the most common situation.

Many asynchronous processes such as API calls include a completion closure, and the most common way to provide it is as an inline closure. In this example, we’re storing the API request object that is created by the call to our API client so that we can allow the user to cancel the request if it’s taking too long. Let’s assume this code appears in our LoginViewController class.

[gist https://gist.github.com/JoshuaSullivan/34cdb4315d79b0a1d85d file=”ForgotCaptureSemantics.swift”]

Whoops! The compiler is mad at us because we have calls to other methods in the class which have an implicit self in front of them. Swift requires that you be explicit about capturing references to objects to avoid unexpected behavior. Fine, let’s add self:

[gist https://gist.github.com/JoshuaSullivan/34cdb4315d79b0a1d85d file=”StrongCaptureSemantics.swift”]

Better! However, the closure is now holding a strong reference to self and the LoginViewController is holding a strong reference to the closure. This creates a retain cycle and will cause the LoginViewController to be kept alive, even if the user navigates away from this screen. Even if the login was successful and the completion closure was invoked, it still exists and maintains its capture of self unless you explicitly nil the reference as part of the completion. We don’t want to go leaking view controllers all willy-nilly, so let’s try that [unowned self] thing we saw in some WWDC video:

[gist https://gist.github.com/JoshuaSullivan/34cdb4315d79b0a1d85d file=”UnownedCaptureSemantics.swift”]

Right, now we definitely don’t have a strong reference to self! However, users are reporting the app is crashing when login is taking too long and they leave the screen before it completes. Looking at the crash logs, you see a rash of EXC_BAD_ACCESS events occurring. Because you declared self was unowned, it was deallocated when the users left the screen, but when the API call completed, it attempted to call the methods referenced in the closure to disastrous effect.

Using unowned as a capture semantic is the equivalent of force-unwrapping an optional. It’s never a great idea and should only be done when you are 100% sure there’s no chance the captured object will be deallocated before it is invoked. When you’re dealing with long-running asynchronous tasks like API requests, this is a bad bet unless the originating class is a singleton or some other pattern which will guarantee the object exists for the lifetime of the app.

For all other cases, consider this pattern using weak capture semantics:

[gist https://gist.github.com/JoshuaSullivan/34cdb4315d79b0a1d85d file=”WeakCaptureSemantics.swift”]

The secret sauce is line 4, where we guard against the possibility that the LoginViewController was deallocated prior to the API request completing. If self no longer exists, it doesn’t care about the API result, and we can bail out of the closure right away. We simply use the strongSelf reference for the remainder of the closure to avoid unwrapping self at every step and we’re good to go!

Why you shouldn’t mourn the removal of –, ++ and C-style for loops from Swift

One of the neatest things about Swift going open-source earlier this year is that the deliberation process for the future of the language, including breaking changes to the syntax, is out in the open. Case in point are the two accepted proposals to remove the unary -- and ++ operators and to remove C-style for loops.

The case against — and ++

View the proposal.

Chris Lattner, the principle architect of Swift, has stated in the past that the ++ and -- operators were added very early in Swift’s inception simply because Objective-C had them. Now that Swift has had a chance to mature, there are a few factors which indicate they are a poor fit for the language. First and foremost is that they are confusing as hell to programmers who haven’t already spent time banging their heads against them in one of the C-derived programming languages. Consider this case:

[gist https://gist.github.com/JoshuaSullivan/72cfabb9ac63aa2721d5 file=”IncrementDecrementExample.swift” /]

The trailing versions of these operators are particularly confusing, where the value is being returned prior to being changed. This difference in pre- and post-incrimenting of the variable is a particularly fruitful source of errors in code, with things like index values going out of range or holding unexpected values because the wrong operator was used.

The strongest case for keeping them is their brevity, but Swift does not favor brevity over security and, as Chris Lattner points out, the more expressive n += 1 is hardly an onerous amount of typing. The main use for the operators seems to be in C-style for loops (based on a survey of Swift-based GitHub projects). Thus, with the imminent removal of those for loops from the language, the main use-case for the operators will die with them.

The case against C-style for loops

View the proposal.

The C-style for loop, like the unary increment and decrement operators, were added early in Swift’s development simply because Objective-C had them. As Erica Sadun so eloquently points out in her proposal, they’re a hold-over from an earlier era of programming and have a complex and error-prone syntax. They accomplish nothing which can’t be accomplished in a more succinct and expressive fashion using the Swift for in loop. Consider these two examples, both of which combine strings from an array to a base string and prints them out:

C-style for loop
[gist https://gist.github.com/JoshuaSullivan/72cfabb9ac63aa2721d5 file=”CForLoopExample.swift” /]

Note that the for loop syntax is completely non-expressive. There’s no indication of what each of the “;”-separated fields aims to accomplish…you have to already be familiar with it.

Swift map() function
[gist https://gist.github.com/JoshuaSullivan/72cfabb9ac63aa2721d5 file=”MapExample.swift” /]

“But wait,” you might say, “I need the index value as well!” There are a couple of ways to do it in Swift without relying on C-style for loops:

Method 1: enumerate()
The handy enumerate() method is present on all collections conforming to SequenceType is one way:
[gist https://gist.github.com/JoshuaSullivan/72cfabb9ac63aa2721d5 file=”EnumerateExample.swift” /]

Method 2: for-in over a Range
[gist https://gist.github.com/JoshuaSullivan/72cfabb9ac63aa2721d5 file=”IterateRangeExample.swift” /]

The 2nd method is stylistically closest to the C-style for loop, but it is still much easier to understand what values i will hold and isn’t subject the problem of a statement inside the for loop modifying the index and causing it to go out of bounds (i is constant).

Conclusion

It can feel a little jarring to lose language features, but with some thought it is clear to see that the removal of these 2 features will result in a language that is more expressive and less error prone.

Don’t use Swift enums to contain magic strings!

At first glance, using a Swift enum with a raw type of String seems to be a great way to package (or, if you like, enumerate) magic strings used by things like Notifications:

[gist https://gist.github.com/JoshuaSullivan/cb6d0c6dcfde3f20b43b file=”EnumExample.swift” /]

However, this is a poor application of the Swift enum for the following reason: you are not interested in the enum case, only its raw value. Any place you want to use the magic string in your code you’re forced into fully qualifying the enum case (because the argument type is a string, not the type of your enum) and then accessing the rawValue property.

A better approach is to use a Swift struct with static constant string members defining the magic strings:

[gist https://gist.github.com/JoshuaSullivan/cb6d0c6dcfde3f20b43b file=”StructExample.swift” /]

The look is very similar to an enum, but in practice it ends up being shorter and cleaner to use:

[gist https://gist.github.com/JoshuaSullivan/cb6d0c6dcfde3f20b43b file=”Usage.swift” /]

Now, this argument is moot if you have a situation where methods in your classes take your enum type as an argument and use the rawValue at some point internally, but for things like userInfo dictionary keys, user defaults keys, notification names, segue names, etc. you are better off with the struct approach, since the string is all you’re interested in.

2015-12-16 Addendum:
As with any advice on using Swift, this should not be viewed as an Immutable Truth of the Universe™. There are still situations when an enum would be a perfectly reasonable container for your strings: namely, when you have a model built around the use of the enums and not just the strings they contain.