Singleton (aka. Wrapper) allows behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same class.

Structure

Class diagram (UML):

Singleton Class Diagram (UML)

When Would You Use It?

  • You want to add responsibility to individual objects dynamically and transparently without affecting other objects.
  • You want to extend the behavior of a class that is impractical to do so. A class definition may be hidden and unavailable for subclassing—or each behavioral extension to a class would require a tremendous amount of subclasses to support each combination of features.
  • Extended responsibilities of a class can be optional.

Related Patterns

Many patterns can be implemented using the Singleton pattern. See Abstract Factory, Builder, and Prototype.

Discussion

Singletons and Thread Safety

About thread safety, normally there are two cases to consider when using signleton:

  • during initialization of the singleton instance
  • during reads and writes to the instance

References

  • Design Patterns: Elements of Reusable Object-Oriented Software, by Book by Erich Gamma, John Vlissides, Ralph Johnson, and Richard Helm (GoF)
  • Pro Objective-C Design Patterns for iOS, by Carlo Chung
  • Pro Design Patterns in Swift, by Adam Freeman

Example #1 – Database Connection

Code

import Foundation
import UIKit

/**

Singleton class for "Database Connection"

It is working with Swift 1.2 or above, since class constant is introduced.For "earlier" version, use "nested struct". 

    // nested struct
    class SingletonB {
        class var sharedInstance: SingletonB {
            struct Static {
                static let instance: SingletonB = SingletonB()
            }
            return Static.instance
        }
    }

*/
class DBConnection {

    // singleton instance
    // using "type property" can ensure "thread safety" during initialization.
    static let sharedInstance: DBConnection = DBConnection()

    // other properties
    // if there is a need for "read/write", we also need to consider "thread safety" during the read/write precedure. Use "dispatch_async" or "dispatch_sync".
    var usingCount: Int = 0

    // use "private" to prevent accessing from outside
    private init() {

        // 
        println("A signleton instance initialized.")
    }

    // normal fucntions
    func doConnectionWork() {

        // do coonection work....

        // increase the "using count"
        usingCount++
    }
}

var dbConn1 = DBConnection.sharedInstance
dbConn1.doConnectionWork()
var dbConn2 = DBConnection.sharedInstance
dbConn2.usingCount
dbConn2.doConnectionWork()
dbConn2.usingCount
dbConn1.usingCount

// Another new instance. Normally cannot be instantiated outside.
var dbConnAnother = DBConnection()
dbConnAnother.usingCount

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>