Three Swift Anti-patterns

Joseph Petrich Sr.
4 min readFeb 16, 2018

--

As Swift is a newer programming language, there are fewer resources about practical software development in Swift than there are about older object-oriented languages like Java and C# and most Swift tutorials focus on recommended best practices. Swift is a powerful language that lets you do a lot with modern language features like optionals, functions as first-class objects, and higher-order functions, and also includes some relatively novel convenience functionality like extensions and multiple return values. All this makes for a language that is rewarding to use, but this wealth of functionality can also can lend itself to some bad habits. In this post, I cover three common anti-patterns, or bad habits, that are easy to fall into when using Swift for iOS development.

Force Unwrapping Optionals

It’s very convenient to force-unwrap an optional when you think you know that a variable is not nil. Consider the following example:

This type of force-unwrapping is very tempting. You have a class, Mouse, that you want to implement an existing protocol, Pluralizable for its convenient API that includes a method for pluralization. You go ahead and implement this method, and try to implement it with a simple if number > 1 statement, but you get a compilation error about number being optional. You can’t think of a case where number would be nil, so you throw in an exclamation point to force-unwrap, as Xcode so helpfully suggests, and you go on your merry way. This is problematic because you shouldn’t profess to conform to a protocol unless you conform to the spirit of that protocol. Force-unwrapping the protocol-defined function argument is like putting a fatalError() call in one of your API methods. The protocol defined the argument as optional, so your implementation needs to handle that case. The safe implementation is hardly more code, and handles the nil case gracefully:

Declaring View Controller Properties As Required

Consider the following snippet of a view controller that displays information about a given animal.

Because this view controller is part of an iOS app, and is connected to a view controller in a Storyboard, it expects animalToDisplay to be passed in from its presenting view controller. This is a fine expectation, and a commendable alternative to another anti-pattern, having a singleton which stores the currently displayed animal. However, there’s a maintainability problem here, in that there is no way to force the presenting view controller to set animalToDisplay, so viewDidLoad could get called without animalToDisplay being set and the app would crash. If you are using Storyboards, you don’t have the option of using a custom initializer, so your two options are giving animalToDisplay a default value, or declaring it as optional. Both could be reasonable solutions depending on the use case, and both are preferable to having a required property on your view controller.

Adding Unrelated Methods To Protocols

Swift doesn’t allow optional methods on protocols like Objective-C does, but you can accomplish the same functionality either by cheating and adding the @objc annotation before your protocol, or by providing a default empty implementation for a protocol method in an extension to that protocol. Because of this, it can be tempting to add methods to protocols your classes already implement to avoid the (actually small) overhead of writing new protocols and implementing them. As an example, say you are building an app for showing information about animals called iZoo. You decide a feature of iZoo should be an animal recognizer for identifying animals at the zoo. A friend of yours works on that module and makes it a nice packaged framework called ZooVision. You use an analytics module you’ve built already called Zoolytics and add it as a dependency of both iZoo and ZooVision. There is a nice protocol in Zoolytics that your UIViewControllers can implement to easily add analytics to any view. You launch the app and it starts doing well, so you decide to add an ads capability. You want to monetize the app quickly, so you just add it into Zoolytics rather than creating a new module that both iZoo and ZooVision would need to depend upon, and add some methods to your analytics protocol to allow showing ads on any view. It is a convenient solution, but makes the code less maintainable because it is not clear where the ads functionality is coming from, it makes the code less testable, because you no longer have separation of responsibility, and it makes it more difficult to enhance any one component without possibly affecting everything else.

Let me know in the comments what you thought about this post! Do you think any of these anti-patterns are actually best practice? I’d love to hear what other anti-patterns you have seen in your Swift development.

--

--