Open In App

Singleton Class in Objective-C

Last Updated : 01 Dec, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Objective-C serves as a programming language widely employed to construct applications intended for both macOS and iOS. Among the many design patterns that find extensive usage in Objective-C, the Singleton pattern proves quite noteworthy. A Singleton represents a class in that instantiation remains restricted to a single instance throughout the entire application. In this discourse, we delve into the Singleton pattern and its implementation in Objective-C.

What is a Singleton Class?

The Singleton paradigm denotes a class instantiation restricted to a singular occurrence across the entire application. It establishes a global access point allowing all objects to connect with it. Such a pattern is preferred for shared resources, enabling a sole entry point, thus minimizing resource creation redundancies.

Benefits of Singleton Class

  • Provides a single point of access to shared resources.
  • Ensures that these resources are not created unnecessarily.
  • Can improve performance by reducing memory allocation.

Implementing Singleton Class in Objective-C

There are two approaches to implementing a Singleton class in Objective-C:

Approach 1: Using a Static Instance Variable

This method involves using a static instance variable to retain the sole instance of the class, with the variable initialized to nil when the class is first loaded. Upon the calling of the shared instance method, an assessment is conducted to determine if the instance variable is nil. Should it be found empty, a new class instance is generated, and assigned to the variable. On the other hand, if it is non-nil, the current class instance is returned.

Below is the Objective-C program to implement a singleton class using static instance variables.

ObjectiveC




// Objective-C program to implement
// static instance variables
 
// Importing the Foundation framework
// which includes NSObject and other classes
#import <Foundation/Foundation.h>
 
// Declaring the interface for our singleton class
// and conforming to the NSCopying protocol
@interface MyClass : NSObject <NSCopying>
 
// Declaring the sharedInstance method which
// returns a MyClass instance
+ (MyClass *)sharedInstance;
 
@end
 
// Defining the implementation for our
// singleton class
@implementation MyClass
 
// Declaring the static variable which will hold
// the shared instance of MyClass
static MyClass *sharedInstance = nil;
 
// Implementing the sharedInstance method
+ (MyClass *)sharedInstance
{
  // Checking if sharedInstance is nil (i.e.
  // the shared instance hasn't been created yet)
  if (sharedInstance == nil)
  {
    // Creating a new instance of MyClass using
    // the superclass's allocWithZone method
    sharedInstance = [[super allocWithZone:NULL] init];
  }
   
  // Returning the shared instance
  return sharedInstance;
}
 
// Overriding the allocWithZone method to always
// return the shared instance
+ (id)allocWithZone:(NSZone *)zone
{
  return [self sharedInstance];
}
 
// Overriding the copyWithZone method to always
// return the same instance (since this is a singleton)
- (id)copyWithZone:(NSZone *)zone
{
  return self;
}
 
// Implementing the init method to initialize any
// instance variables (if needed)
- (id)init
{
  self = [super init];
  if (self != nil)
  {
    // Initialize instance variables here
  }
  return self;
}
 
@end
 
// Main function for testing our singleton
int main(int argc, const char * argv[])
{
  // Creating two instances of MyClass using
  // the sharedInstance method
  MyClass *myObject1 = [MyClass sharedInstance];
  MyClass *myObject2 = [MyClass sharedInstance];
   
  // Checking if both instances are the same (i.e.
  // the sharedInstance method is working correctly)
  if (myObject1 == myObject2)
  {
    NSLog(@"Both objects are the same instance");
  }
  else
  {
    NSLog(@"Objects are different instances");
  }
   
  // Returning 0 to indicate successful completion
  // of the program
  return 0;
}


Output:

Using a Static Instance Variable

 

Explanation:

  • The present algorithm generates a singleton class entitled “MyClass” through the initial method, which is done by establishing a static variable that can hold the shared instance. 
  • This class contains the “sharedInstance” method, which determines whether the shared instance has already been generated and, if not, constructs a new instance using the “allocWithZone” technique from its superclass. 
  • It also supersedes the “allocWithZone” and “copyWithZone” methods to make sure that the same shared instance is always given out.
  • In the main function, two instances of the “MyClass” class are generated through the “sharedInstance” technique, and their memory locations are evaluated to verify whether they refer to the same instance or not (which they ought to, given that “sharedInstance” method returns the same instance each time it is accessed). 
  • The program then shows a message stating whether or not the two instances are identical and returns 0 to indicate that the program has concluded successfully.

Approach 2: Using dispatch_once

To guarantee the thread safety of the Singleton class initialization process, the dispatch_once function is utilized in this method. The function is invoked once throughout the entire lifetime of the application, ensuring synchronization and safety. Upon the calling of the sharedinstance method, the dispatch_once function comes into play, generating the sole instance of the class.

Below is the Objective-C program to implement a singleton class using a dispatch_once:

ObjectiveC




// Objective-C program to implement a
// singleton class using a dispatch_once
#import <Foundation/Foundation.h>
 
// Declare an interface for the singleton class
@interface MyClass : NSObject
 
// Declare a class method to get the shared
// instance of the class
+ (MyClass *)sharedInstance;
 
@end
 
// Implement the interface for the singleton class
@implementation MyClass
 
// Create a static variable to hold the shared
// instance of the class
static MyClass *sharedInstance = nil;
 
// Define the class method to get the shared
// instance of the class
+ (MyClass *)sharedInstance
{
  // If the shared instance is nil, create it
  if (sharedInstance == nil)
  {
    sharedInstance = [[super allocWithZone:NULL] init];
  }
     
  // Return the shared instance
  return sharedInstance;
}
 
// Override the allocWithZone method to always
// return the shared instance
+ (id)allocWithZone:(NSZone *)zone
{
  return [self sharedInstance];
}
 
// Override the copyWithZone method to always
// return the existing instance
- (id)copyWithZone:(NSZone *)zone
{
  return self;
}
 
// Override the init method to always return
// the shared instance
- (id)init
{
  return sharedInstance;
}
 
@end
 
// Define the main function
int main(int argc, const char * argv[])
{
  // Create two instances of the singleton class
  MyClass *instance1 = [MyClass sharedInstance];
  MyClass *instance2 = [MyClass sharedInstance];
   
  // Check if both instances are the same
  if (instance1 == instance2)
  {
    NSLog(@"Both objects are the same instance");
  }
  else
  {
    NSLog(@"Objects are different instances");
  }
   
  return 0;
}


Output:

Using dispatch_once

Explanation:

  • This code creates a “singleton” class called MyClass, which means only one instance of the class can exist at a time. 
  • The code achieves this by creating a static variable that holds the shared instance of the class and overriding certain methods to ensure that the shared instance is always returned.
  • In the main function, two instances of MyClass are created using the sharedInstance method, and the code checks if they are the same object. 
  • Since sharedInstance always returns the same instance of the class, both instance1 and instance2 point to the same object, and the code prints a message confirming this.

Conclusion

Both approaches have their advantages and disadvantages. The first approach is simpler to implement, but it is not thread-safe. The second approach is thread-safe, but it is more complex to implement. It is important to choose the right approach based on the specific requirements of the application.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads