Writing Swifty Code

El gato negro de Juan toma leche. (es)
John’s black cat drinks milk. (en)
O gato preto de João toma leite. (pt)

Languages are different. Some of them look familiar. Some of them share the same ideas of syntax and grammar.

A word by word translation of the first sentence would feel strange but it will convey the same meaning. It might take you a little while to parse it down and understand it.

The cat black of John drinks milk.

People who speak a second language incorporate these idiosyncrasies into their accent.

Something similar happens when learning programming languages. If you have been a C# coder all your life and now you’re learning Swift; chances are you’ll be writing Swift code with a C# accent.

So, let’s try to reduce the accent! 👨🏻

Let your var be declared correctly

In Swift, you can refer to types via mutable and immutable references. For mutable types, you’d use var when declaring variables; for immutable, let.

Mutability

Other programming languages call immutable variables constants but that’s an incomplete description of what let does in Swift. As the example below shows, an immutable reference to a class instance will allow modifying the internals of the instance but not the actual instance reference. However, when using structures instead of classes, let feels more restrictive.

In Swift, types are either value types or reference types. What other languages call primitives Swift implements them as structures. A string, an integer, and a boolean are structures in Swift.

let number = 42
number = 46 // Doesn't compile

// MARK: Classes

class Person {
var name = “”
}

let person = Person()
person.name = "Carlos"
person.name = "Madrigal" // Compiles

// Create another person and assign it to the same variable
person = Person() // Doesn't compile

// MARK: Structures

struct Dog {
var name = ""
}

let dog = Dog()
dog.name = "Chester" // Doesn't compile

If you’re coming from Objective C, you’re used to having pairs of classes for immutable and mutable versions of a concept. For example, NSString and NSMutableString are the immutable and mutable versions of a text string.

However, in Objective C you could still have a const pointer to a NSMutableString instance. That means you can change the internals of the string but you cannot assign something else to the constant reference pointer.

In Swift, String is a structure and follows structure mutability semantics. In fact, Swift is crazy about structures. If you look into the Swift Standard Library you’ll notice there’s only one class, a bunch of protocols, and a bunch of structures. If you’re not aware of the difference in immutable semantics between class and structure types, you’ll get confused because there’s a high chance you’ll end up using structures.

Initialization

Another misconception is people think let statements require an initialization right away. When these people can’t provide an initial value, they flip the let to a var.

// Code smell
var value: Int?
if someCondition
value = 6
else
value = 9

// Use let instead: perfectly valid! Also, avoid the optional!
let value: Int
if someCondition
value = 6
else
value = 9

The idea here is that let demands only one initialization but it doesn’t need to be on the same line. This is particularly true for properties. Sometimes, some coders declare everything using var because they will assign a value in init().

class PersonaView: UIView {
var imageView: UIImageView?

required init() {
imageView = UIImageView(image: UIImage(named: "face")!)
}

required init?(coder aDecoder: NSCoder) {
fatalError("Not implemented")
}
}

That’s a code-smell.

After the initialization imageView is practically a constant — i.e., once you get the initial reference and set it up you won’t assign a whole new reference to the same variable.

Every access to that reference needs to be handled with care because it’s an optional.

Developers consuming this code could do something like assigning a new reference to the property and that can cause funky things inside your class like never getting events from the image view and memory leaks because your code might be listening to some other image view’s events.

let view = PersonaView()
view.imageView = UIImageView(image: UIImage(named: "stupid"))

But all of that easily goes away when you use let instead.

class PersonaView: UIView {
let imageView: UIImageView

required init() {
// This is the place to initialize your variables
imageView = UIImageView(image: UIImage(named: "face"))
}

required init?(coder aDecoder: NSCoder) {
fatalError("Not implemented")
}
}

let view = PersonaView()
view.imageView = anotherImageView // Doesn't compile

Now that we’re talking about initializers, if you need to call an initializer on super, make sure you assign all your immutable variables before calling super or self. You can use self when disambiguating between a property and a parameter.

class PersonaView: UIView {
let imageView: UIImageView
let actionButton: UIButton
let compact: Bool

required init(compact: Bool) {
// This is the place to initialize your variables
imageView = UIImageView(image: UIImage(named: "face")!)
actionButton = UIButton(type: .custom)

// You can use self in cases like this
self.compact = compact

super.init(frame: CGRect.zero)

// After calling super.init or self.init, then
// you can use self.
actionButton.addTarget(self,
action: #selector(tapHandler),
for: .touchUpInside)
}

required init?(coder aDecoder: NSCoder) {
fatalError("Not implemented")
}

func tapHandler() {
}
}

Understanding how to use let should yield clearer code because now mutability semantics really represent your intentions as a Swift coder. It also helps you avoiding optionals but we’ll talk more about them in the next section.

The private(set) code smell

Sometimes, C# developers use private(set) for properties with public getters but private setters. Most of the times though, the private setter is only used in the constructor. If that’s the case you’re implementing in Swift, you should stop using private(set) and use let instead. You’re going to increase code simplicity and readability with simple lets and preserve the semantics.

class CSharpEmployee {
private(set) var id: String?
private(set) var name: String?

init(id: String?, name: String?) {
// Only place where these properties are set
self.id = id
self.name = name
}

override func description() -> String {
return "\(id): \(name)"
}
}

class SwiftyEmployee {
let id: String?
let name: String?

init(id: String?, name: String?) {
self.id = id
self.name = name
}

override func description() -> String {
return "\(id): \(name)"
}
}

Recommendation

Swift loves the principle of least privilege. You can feel it when you learn its syntax. As a rule of thumb, start with let. Flip to var only when you want mutability.

Optional pain

Swift provides a superb support for optional and non-optional variables. When used correctly, they are powerful, expressive, and safe.

The problem, though, is that this concept looks familiar to nullable types in other programming languages.

For example, for C# programmers, a nullable is a type that besides holding a value within a specific range, it can also hold null. A Nullable<int> or int? can hold any integer in the Int32 value range plus null. Nullable types are meant to represent primitive value types in a context like databases where sometimes you need to represent the absence of a value.

Cool. We got the C# refresher down. However, Swift optionals are not the same.

In Swift, an optional is a variable that can hold nil as a value. Any type can be optional. You can have an optional value type like in C#. You can also have an optional reference type. The power is not about having references that can have nil; the power resides on having references that won’t accept nil as a value.

For example, declaring a variable as a non-optional will make the compiler work for you.

var imageView: UIImageView = nil // Doesn't compile

In this case, UIImageView is a class type. In other programming languages, reference type variables always accept null and there’s no way to enforce not accepting null.

Let that concept sink in.

Have you ever thought of how many lines of code you need to write just to check your arguments are not nil? Being a C# or Objective C programmer you must be able to recall code snippets like the following:

// C#
void someMethod(string paramA, string paramB) {
if (paramA == null) {
throw new ArgumentNullException("paramA")
}
if (paramB == null) {
throw new ArgumentNullException("paramB")
}
// Do something
}

// Objective C
- (void)someMethodWithParamA:(NSString *)

C# is more verbose but you have to do something similar in both languages. Over and over again you have to check you have valid references before you start working with them.

The same in Swift looks like this:

func someMethod(paramA: String, paramB: String) {
// Do something
}

There’s no need to check for nullability. Period.

Having said that, a common code-smell is to have lots of variable or parameter declarations as optional or optional implicit.

var imageView: UIImageView!
var dataSource: DataSource?

In Swift, optionals explicitly say you are going to manage nullability checks — a.k.a., if-let checks. For optionals, it’s expected to see this:

if let imageView = imageView {
// Do something with the image view
}

You can also do this at your own risk:

let size = imageView?.image?.size
// ???: What's the type of `size`? `CGSize` or `CGSize?`?

let width = size?.width
// ???: What's the type of `width`? `CGFloat` or `CGFloat?`

It happens that newbie coders don’t learn this Swift concept and get frustrated with the compiler. They turn to StackOverflow to find someone saying “use ! instead of ?”.

let size = imageView!.image!.size
// Read ! as "it has the potential to crash--and it will"

let width = size.width

You should use implicit unwrapping with a lot of care. If you happen to see lots of question and exclamation marks in your code it’s because your code smells too much 💩. Consider refactoring it.

Optionals in view controllers

Are you ready to stop using optionals — implicit or not? Cool. I find myself not following my own recommendation when coding view controllers.

View controllers are not necessarily immediately displayed. You can new up a view controller reference and keep it around. Then some time later the user does something that causes that view controller to display its view. View controllers load their views lazily. For that reason, often times you end up setting up your UI controls in viewDidLoad(). With lazy loading, you need to have the references to the UI controls optional.

The view load pattern in a view controller is stable. Once viewDidLoad() executes you should have access to the UI controls you need. Consider using implicit optional for those references to avoid nullability checking.

On the other hand, you could opt to use immutable non-optional references and new everything up in the initializer. The disadvantage to this approach would be memory consumption.

Recommendation

Again with the principle of least privilege: use non-optional whenever possible. In fact, combine both recommendations, use non-optional immutable variables whenever possible and open up as needed.

Initializer Patterns

When creating view controllers programmatically you often end up doing this:

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

First of all, it’s totally fine. Let’s try to understand why.

  • In Swift, an initializer must initialize its own non-optional properties before calling it’s superclass’s designated initializer.
  • A designated initializer is the main initializer in a type. A designated initializer calls an initializer from its immediate superclass.
  • On the other hand, a convenience initializer is a utility one; it makes initialization easier. A convenience initializer calls another initializer from the same class that eventually calls a designated initializer.
  • A required initializer is an initializer that needs to be overridden in subclasses. You don’t include the override keyword when overriding a required initializer.
  • A failable initializer is one that can return nil instead of an actual instance.

In this case, the code shown above, is overriding a required failable initializer. Since your code doesn’t use storyboards, it’s okay to use fatalError() to crash the app. If you want to use storyboards then you would need to refactor that code.

Migrating to Swift 3

You should read about the details on migrating your projects to Swift 3. Here I will summarize the most obvious one: naming conventions.

Swift is the clearest language I’ve ever worked with. Part of that clarity comes with the new naming guidelines. You should read them over and over again. After you read them, you should recognize the following paragraph:

Clarity at point of use is your most important goal. Entities such as methods and properties are declared only once but used repeatedly. Design APIs to make those uses clear and concise. When evaluating a design, reading a declaration is seldom sufficient; always examine a use case to make sure it looks clear in context.

Clarity at point of use means clarity when consuming your code. We as developers spend a lot of time reading code compared to the time we spend writing code. We don’t want to repeat the PERL experience where you encrypt as you type🔒.

The first thing you’ll notice is that in Swift 3 the label for the first argument is now required.

// Swift 2.3
func distanceFromPoint(point: Point, to: Point)
distanceFromPoint(p1, to: p2)

// Swift 3
distanceFromPoint(point: p1, to: p2)

Notice that the Swift 3 version now looks redundant: “distance from point point p1 to p2”. We should rename it to something like:

// Swift 3
func distance(fromPoint: Point, to: Point)
distance(fromPoint: p1, to: p2)

This renamed version reads as “distance from point p1 to p2”. It reads way better.

Xcode comes with a conversion tool that doesn’t do a terrific job. It might get your code close to compiling but with awful naming conventions. The tool might do something like this:

func distanceFromPoint(_ p1: Point, p2: Point)

The underscore makes the first label implicit — like in Swift 2.3. That code compiles but it doesn’t follow Swift 3 naming conventions. You can leave it there but it looks lazy, incomplete and foreign.

Again, you should read the API Design Guidelines to understand the changes. Every other Swift 3 related change cascades from that. The Swift Standard Library changed, all the kits changed as well. Since everything changed, now you have to adjust your code to talk to the new names of the APIs you were using.

When in doubt, look at the Swift Standard Library or UIKit. Check how native language speakers speak the language and try to imitate them in your code.

Some code-smells I often see are:

  • I bet coders are lazy when I see class names ending in -Manager, -Helper, and -Utils. These suffixes often show coders didn’t want to spend time thinking where to place code. -Manager classes end up being god classes doing everything or a substitute to have almost-global variables. -Helper classes could be implemented as categories or extensions. -Utils classes often end up doing work across tiers — a.k.a., spaghetti code. In fact, reading -Helper, -Manager, and -Utils every few lines gets tiring too.
  • There’s no better indicator of having an accent in Objective C or Swift than having getter methods that have the get prefix. Pay attention to UIKit for example, you just don’t see the get idiom like you do in C# or any other language. In Objective C and Swift code you omit get like in viewController.subviews or view.layers.
  • In Objective C and Swift, acronyms and initialisms use upper casing. Think of NSURL not NSUrl. It should be JSON not Json, you’re thinking C# there.
  • Avoid using self. If you use self for autocompletion, please stop. In Swift, you use lots of blocks. Inside those blocks you have to use self when referring to instance variables. That’s another way Swift is screaming at you “you’re creating a closure; check you don’t have cyclic references!”. If you see self everywhere — because of your laziness — then you’re probably going to miss possible cyclic references and probably won’t declare self as weak; which in turn will cause memory leaks. Those bugs 🐞 are very hard to find and fix; help your self by not writing self.
  • Avoid redundancy. If your project name is MyAwesomeProject and you have a MyAwesomeProjectManager class that uses a MyAwesomeProjectSettings class that will become very tiring very soon. Swift projects are namespaced. So, if you call your project MyAwesomeProject call the other classes Manager and Settings. In fact, read my point about -Manager classes and see if you can rename it. You want to make it clear at point of use; if everything is a manager then you’re not helping. Another form of redundancy is when you leave template code in your code, like the following snippet. Remove it. Make your code clearer.
func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}

Scope Access Modifiers

Finally, I want to talk about scope access modifiers because they changed in Swift 3. If you had private in Swift 2.3 you’ll see them as fileprivate in Swift 3. What used to be public now is open. The semantics stayed the same but the new words better represent those semantics. In Swift 2.3 private meant file private and public meant public and open for subclassing. Swift 3 access modifiers are more precise; now private really means private and public means public but closed for subclassing.

Conclusion

Swift syntax accomplishes something you rarely see in other programming languages. Swift talks to you and it talks to you all the time. For example, the question mark is how Swift tells you “you may not have a value here”. The exclamation point is the way Swift screams at you: “this is dangerous and may crash, proceed at your own risk”. There are keywords like escaping, unsafe, open, fileprivate that help us achieve clarity at point of use.

If you want to be a better coder, consider having a second look at the principle of least privilege and learn how to hide your internals; you have a good set of scope access and mutability modifiers in Swift. Also, check out the Single Responsibility Principle to avoid creating god methods and classes and kill all your -Manager, -Helper, and -Utils classes — use extensions more, they’re meant for cases like those. Follow the Don’t Repeat Yourself — a.k.a., DRY — principle to avoid code duplication. And with all this new knowledge Keep It Silly Simple — a.k.a., KISS — and avoid mutable optionals whenever possible and, with them, avoid lots of nil checks. Follow naming conventions, that’s the best form of code documentation because the documentation evolves as you evolve your code. Spend some time thinking about the names you pick; they must clearly represent your types, variables, and methods.

I’m not a native English speaker. I speak Spanish; Mexican Spanish. In fact, I’m from the north of Mexico and my accent is not the same as Mexico City’s. When I meet people from Mexico City they immediately notice my accent but the funny thing is they think they don’t have one. It’s not until I mimic their accent when they realize they do have one. The same happens in every natural language and I bet it happens for computer languages too but we just don’t point out the differences. I’m not saying that speaking with an accent is a bad thing but it sure does feel foreign when your accent is different from the rest. Coding with an accent does feel foreign as well and maybe, by pointing out the accent, we can minimize it. Computer languages are super easy in comparison to natural languages. I bet you can remove your computer language accent with minimal effort and, if not, these insights might help you become a better Swift coder. ☺️

¡Gracias por leer! Carlos Madrigal

Show your support

Clapping shows how much you appreciated Carlos Madrigal’s story.