Monday, April 27, 2015

Design Patterns: Singletons

Design patterns are often considered a more advanced topic and therefore ignored or overlooked by people new to iOS or OS X development. However, there are a number of design patterns every aspiring iOS or OS X developer will be faced with from day one. The singleton pattern is one such pattern.

Before we start looking at techniques to implement the singleton pattern in Swift and Objective-C, I'd like to take a moment to understand the singleton pattern, including its advantages and disadvantages.

1. What Is a Singleton?

True & Functional Singletons

The singleton pattern is inextricably tied to object-oriented programming. The definition of the singleton pattern is simple, only one instance of the singleton class can be created or is alive at any one time.

Brent Simmons, however, nuances this definition by making a distinction between true singletons and functional singletons. Brent defines true singletons as classes that always return the same instance of itself. It is not possible to create more than one instance of the class. Functional singletons are created once and used in several places.

I'm sure many developers wouldn't categorize functional singletons as singletons, but I like the distinction Brent makes. Functional singletons often lack the disadvantages typical to true singletons. We'll look at these disadvantages later in this article.

If you're familiar with iOS or OS X development, then you'll notice that Apple's frameworks make use of the singleton pattern. An iOS application, for example, can only have one instance of the UIApplication class, which you can access through the sharedApplication class method.

Even though the UIApplication class gives you access to the UIApplication singleton, nothing prevents you from explicitly instantiating a UIApplication instance.

The result, however, is a runtime exception. The exception clearly states that only one instance of the UIApplication class can be alive at any one time. In other words, the UIApplication class was designed with the singleton pattern in mind.

Advantages

Accessibility

The most obvious advantage of the singleton pattern is accessibility. Consider the UIApplication class as an example. By importing the UIKit framework, the UIApplication singleton is accessible from anywhere in your project. Take a look at the following example of a UIViewController subclass.

Control and Behavior

It is sometimes useful or essential that only one instance of a class is alive at any one time. The UIApplication class is an example of this requirement. Other examples may include classes for logging, caching, or I/O operations.

That said, it is important to understand that singletons are a means to accomplish control and behavior. Defensive coding techniques can give you the same result without the mental overhead of the singleton pattern.

Disadvantages

Global State

By creating a singleton, you're essentially creating global state. It's important that you're aware of this. A few years ago, Miško Hevery wrote a great article about the singleton pattern in which he explains why the pattern should be avoided. Miško emphasizes that global state is the main reason why singletons are harmful.

There are exceptions though. For example, singletons that are immutable can do little harm. You're still creating global state, but that state is immutable. Miško also mentions loggers as a—somewhat—acceptable application of the singleton pattern since state flows in one direction, from your application into the logger.

Tight Coupling

Most object-oriented programming languages consider tight coupling of modules a bad practice. Put differently, it is recommended to decouple modules as much as possible. This puts the singleton pattern in a bad place and singletons are therefore considered a bad practice by many respected programmers. Some developers go as far as considering it an anti-pattern that should be avoided.

To better understand the problem, consider the following scenario. You've created an iOS application with a networking component in which you access the UIApplication singleton. Your iOS application is such a success that you consider creating an OS X application. The UIApplication class, however, is not available on OS X due to the lack of the UIKit framework. This means that you will have to refactor or modify the networking component of the iOS application.

There are a number of solutions to solve this problem, but the point I want to make is that you have tightly coupled the networking module to the UIKit framework, the UIApplication class in particular.

Reusability

Tight coupling is often closely associated with reusability. A tightly coupled object graph is very often difficult to reuse without refactoring. Poor reusability is sometimes unavoidable, but it is certainly something to keep in mind when developing software.

2. Creating a Singleton

Objective-C

Creating a singleton in Objective-C is very easy to do. In the following code snippet, we create and implement a logging class, Logger. We access the singleton object through the sharedLogger class method.

The implementation is simple. We declare a static variable _sharedInstance that will hold a reference to the singleton object. We invoke dispatch_once, a Grand Central Dispatch function, and pass in a block in which we initialize an instance of the Logger class. We store a reference to the instance in _sharedInstance.

The dispatch_once function ensures that the block we pass it is executed once for the lifetime of the application. This is very important since we only want to initialize one instance of the Logger class.

The oncePredicate variable that is passed as the first argument of the dispatch_once function is used by the dispatch_once function to ensure that the block is executed only once.

The sharedLogger class method returns the Logger instance by returning the reference stored in _sharedInstance. The implementation of sharedLogger may look daunting at first, but I'm sure you agree that the idea is very simple.

Swift

To implement the singleton pattern in Swift, we make use of class constants, which were introduced in Swift 1.2. If you are having issues with the below code snippet, then make sure that you are using Xcode 6.3+.

Let me walk you through the short implementation of the Logger class. We start by declaring a class named Logger. To implement the singleton pattern, we declare a type property, sharedInstance, of type Logger.

By using the static keyword, the sharedInstance constant is tied to the Logger class instead of instances of the class. The sharedInstance constant is referred to as a type property since it is tied to the type, that is, the Logger class. We access the singleton object through the Logger class.

You may be wondering why we don't use the dispatch_once function like we did in the Objective-C implementation. Under the hood, Swift already uses dispatch_once when initializing static constants. That's something you get for free in Swift.

Another common approach for implementing the singleton pattern is by leveraging nested types. In the following example, we declare a computed type property, sharedInstance, of type Logger. In the closure of the computed type property, we declare a structure named Singleton. The structure defines a constant type property, instance, of type Logger.

Accessing the singleton object is the same for both strategies. If you are using Swift 1.2, then I recommend using the first approach for its brevity and simplicity.

3. When To Use Singletons?

I suppose it is tempting, if the only tool you have is a hammer, to treat everything as if it were a nail. — Abraham Maslow

When I first heard about the singleton pattern, I was excited about how useful it would be in my next project. It is very tempting to use a tool that seems to solve many problems. At first glance, the singleton pattern may look like a silver bullet or a golden hammer, but that is not what the singleton pattern is.

For example, if you're using a singleton only to make it easily accessible, then you may be using the singleton pattern for the wrong reasons. It's not because Apple uses the singleton pattern in its own frameworks that it is the right solution to every problem.

Singletons can be very useful, but they are considered an anti-pattern by many experienced programmers. Most of them have had bad experiences with the pattern to come to that conclusion. Learn from their mistakes and use them sparingly.

I don't consider the singleton pattern an anti-pattern, but it is a pattern that should be used with caution. If you feel tempted to turn an object into a singleton, ask yourself the question if there is any other way that you could solve the problem. In most cases, the singleton pattern isn't the only solution available. An alternative solution may require more work or a bit of overhead, but it is probably better in the long run.

The functional singletons Brent Simmons refers to are often a perfectly valid alternative to true singletons. There's nothing wrong with creating an instance of a class and passing it to the objects that need it. Consider this approach the next time you are about the create another singleton.

Conclusion

The singleton pattern is simple and powerful, but it should be used sparingly. Some of your colleagues may advise you against it, but I think it's important to consider its use and judge for yourself whether you think it's a useful addition to your toolbox.


by Bart Jacobs via Tuts+ Code

No comments:

Post a Comment