Singleton Design Pattern in Cocoa

Singleton Design Pattern in Cocoa

Written By: Debasis Das (10-Mar-2015)

  • Singleton Design Pattern is used when there can be exactly one instance of a class.
  • Singleton design pattern provides a global point of access to the single instance of the class.
  • The class keeps track of its sole instance and ensures that no other instance can be created.
  • A singleton class prevents other classes from copying, retaining or releasing the singleton instance.
  • The first instance is created lazily and there on the class ensures that no other instance can be created.
  • Cocoa uses shared instance when the singleton pattern is used.
  • Examples of Singleton classes in Cocoa
    • NSApplication (receives events and distributes them to the correct objects via the first responder pattern)
    • The global variable NSApp is a pointer to the shared NSApplication instance.
    • NSWorkspace – communicates with the Mac OSX finder and underlying file systems
    • NSFontManager – represents a collection of all the fonts installed in a system
    • NSDocumentController
    • NSHelpManager
    • NSNull
    • NSProcessInfo
    • NSColorPanel
    • NSFontPanel

Singleton classes in Cocoa has class method with the word shared.
e.g:
NSWorkspace +sharedWorkspace
NSApplication +sharedApplication
A shared object is created where a particular class should be instantiated once and only once.
Singleton classes must

  • Encapsulate a shared resource (NSFont in case of NSFontManager)
  • Provide a standard way to create one shared instance
  • Provide a standard way to access the one shared instance

Guidelines:

  • A reference to the sharedInstance should not be retained.
  • Everytime a reference is required the called must go through the +sharedInstance method.

Thread Safety.

  • If a singleton is required to be used by multiple threads, care should be taken to make the properties as atomic and to use @synchronized() blocks or NSLock instances.

How to design a singleton class?

  • Step 1 : Declare a static instance of your singleton object and initialize it to nil.
  • Step 2 : Name the factory method as sharedInstance or sharedManager and generate an instance if the static instance is nil.
  • Step 3 : Override the allocWithZone: method to ensure that another instance of the class cannot be created directly without using the factory method. Return the sharedInstance
  • Step 4 : Implement the copyWithZone, release , retain, retainCount and autorelease to ensure singleton status

 

Sample Implementation code for a Singleton class in Cocoa

Read more for Sample Implementation

//
//  MySingleton.h
//  SingletonDesignPattern
//
//  Created by Debasis Das on 3/10/15.
//  Copyright (c) 2015 Knowstack. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface MySingleton : NSObject

+(id)sharedInstance;
@end
//
//  MySingleton.m
//  SingletonDesignPattern
//
//  Created by Debasis Das on 3/10/15.
//  Copyright (c) 2015 Knowstack. All rights reserved.
//

#import "MySingleton.h"

@implementation MySingleton

+(id)sharedInstance
{
    
    static MySingleton *myInstance = nil; //Local static variable
    //All access to this local static variable must go through +sharedInstance
    
    if (!myInstance){
        myInstance = [[[self class] allocPrivately] init];
        //Other initialization goes here
    }
    return myInstance;
}

//The allocPrivately method is considered private and is not declared in the class header
+(id)allocPrivately
{
    return [super alloc];
}

+(id)alloc
{
    NSLog(@"%@ : Use +sharedInstance instead of +alloc",NSStringFromClass([self class]));
    return nil;
}

//The below implementation of alloc is also fine where we are redirecting the caller to the sharedInstance. This might be misleading and the caller might believe that the objects being created are different
//+(id)alloc
//{
//    return [self sharedInstance];
//}

+(id)new
{
    return [self alloc];
}

/*
//The following 2 methods need to be overridden in a NON ARC Environment
 
+ (id)copyWithZone:(struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;
+ (id)mutableCopyWithZone:(struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;

+ (id)copyWithZone:(struct _NSZone *)zone 
{
    return self;
}

+ (id)mutableCopyWithZone:(struct _NSZone *)zone 
{
    return [self copyWithZone:zone];
}
*/

@end

Test Code

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    // Insert code here to initialize your application
    MySingleton *singleton1 = [[MySingleton alloc] init];
    NSLog(@"singleton1 %@",singleton1); //Will print null

    MySingleton *singleton2 = [MySingleton sharedInstance];
    NSLog(@"singleton2 %@",singleton2);

    MySingleton *singleton3 = [MySingleton sharedInstance];
    NSLog(@"singleton3 %@",singleton3);
}

2015-03-10 23:02:56.401 SingletonDesignPattern[28050:896228] MySingleton : Use +sharedInstance instead of +alloc
2015-03-10 23:02:56.401 SingletonDesignPattern[28050:896228] singleton1 (null)
2015-03-10 23:02:56.401 SingletonDesignPattern[28050:896228] singleton2 0x618000001a80>
2015-03-10 23:02:56.401 SingletonDesignPattern[28050:896228] singleton3 0x618000001a80>

Singleton Design Pattern using GCD

Sample Code

//
//  KSFileManager.h
//  SingletonDesignPattern
//
//  Created by Debasis Das on 3/12/15.
//  Copyright (c) 2015 Knowstack. All rights reserved.
//

#import <Foundation/Foundation.h>
@interface KSFileManager : NSObject
@property (atomic, retain) NSString *filePath;
+(id)sharedManager;
@end
//  KSFileManager.m
//  SingletonDesignPattern
//  Created by Debasis Das on 3/12/15.
//  Copyright (c) 2015 Knowstack. All rights reserved.

#import "KSFileManager.h"
@implementation KSFileManager

+ (id)sharedManager {
    static KSFileManager *sharedMyManager = nil;
    //Using dispatch_once from GCD. This method is thread safe
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedMyManager = [[self alloc] init];
    });
    return sharedMyManager;
}

- (id)init {
    if (self = [super init]) {
        _filePath = @"Default File Path";
    }
    return self;
}

- (void)dealloc {
    //The dealloc must not
}
@end

Tester Code

-(void)testSingletonUsingGCD{
    KSFileManager *mgr1 = [KSFileManager sharedManager];
    KSFileManager *mgr2 = [KSFileManager sharedManager];
    NSLog(@"mgr1 %@",mgr1);
    NSLog(@"mgr2 %@",mgr2);   
//    2015-03-13 11:29:25.259 SingletonDesignPattern[40520:1379814] mgr1 <KSFileManager: 0x600000001430>
//    2015-03-13 11:29:25.259 SingletonDesignPattern[40520:1379814] mgr2 <KSFileManager: 0x600000001430>
}

Singleton Design Pattern in NON – ARC (Automatic Reference Counting) setup

Sample Code

//  KSManager.h
//  SingletonNonARC
//  Created by Debasis Das on 3/13/15.
//  Copyright (c) 2015 Knowstack. All rights reserved.

#import <Foundation/Foundation.h>
@interface KSManager : NSObject
@property (atomic,retain) NSString *filePath;
+ (id)sharedManager;
@end
//  KSManager.m
//  SingletonNonARC
//  Created by Debasis Das on 3/13/15.
//  Copyright (c) 2015 Knowstack. All rights reserved.

#import "KSManager.h"
static KSManager *sharedKSManager = nil;
@implementation KSManager
#pragma mark Singleton Methods
+ (id)sharedManager {
    @synchronized(self) {
        if(sharedKSManager == nil)
            sharedKSManager = [[super allocWithZone:NULL] init];
    }
    return sharedKSManager;
}

+ (id)allocWithZone:(NSZone *)zone {
    return [[self sharedManager] retain];
}

//+(id)alloc
//{
//    NSLog(@"%@ : Use +sharedManager instead of +alloc",NSStringFromClass([self class]));
//    return nil;
//}

- (id)copyWithZone:(NSZone *)zone {
    return self;
}

- (id)retain {
    return self;
}

- (NSUInteger)retainCount {
    return UINT_MAX; //denotes an object that cannot be released
}

- (oneway void)release {
    // never release
}

- (id)autorelease {
    return self;
}


- (id)init {
    if (self = [super init]) {
        _filePath = @"Default File Path";
    }
    return self;
}

- (void)dealloc {
    NSLog(@"This dealloc method should never be called");
    [_filePath release];
    [super dealloc];
}
@end

Reference:

Posted in Cocoa, Cocoa Touch, Design Pattern, iOS, Objective C Tagged with: , , , , , ,

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>

Recent Posts


Hit Counter provided by technology news