Singleton mode in iOS

Keywords: iOS network

The concept of singletons

A singleton class ensures that there is only one instance object of that class in the application's life cycle and that it is accessible from the outside world.There are many singleton classes in iOS, such as UIApplication,UIScreen,NSNotificationCenter,NSFileManager,NSUserDefaults,NSURLCache,NSHTTPCookieStorage, and so on.

Where to use the singleton mode

Share a resource (this resource only needs to be created once for initialization) throughout the application, typically for tool classes.For example, a project such as a landing controller, network data request, music player, etc. requires multiple controllers or methods.

Single Case Mode Implementation Method

1. Implementation code of singleton mode in ARC environment, taking Singleton class as an example
//.h file
#import <Foundation/Foundation.h>
@interface Singleton : NSObject
//In order to make the instance accessible to the outside world, we usually provide a class method, class method naming specification share class name | default class name | class name
+(instancetype)shareSingleton;
@end

//.m file
#import "Singleton.h"
@implementation Singleton

//0. Provide global variables
static id _instance;

//1.alloc calls allocWithZone:
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
    //Method 1 to implement singleton mode
    /*
    //Mutex Lock Solves Multithreaded Access Security Problems
      @synchronized(self) {
          if (_instance == nil) {
              _instance = [super allocWithZone:zone];
          }
      }
    */

    //Method 2 for implementing singleton mode: Use one-time code provided by GCD
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [super allocWithZone:zone];
    });
    return _instance;
}

//2. Implement class methods (singleton methods)
+(instancetype)shareSingleton
{
    return [[self alloc]init];
}

//3.copy calls copyWithZone at the bottom:
//For strictness, also rewrite copyWithZone and mutableCopyWithZone
-(id)copyWithZone:(NSZone *)zone
{
    return _instance;
}

-(id)mutableCopyWithZone:(NSZone *)zone
{
    return _instance;
}
2. Implementation Code of Single Case Mode in MRC Environment

Rewrite the following three methods from the ARC code

/*ARC Code snippet, see above*/

//Do nothing to ensure that the singleton object is not destroyed
-(oneway void)release{}
//Return itself guarantees only one singleton object
-(instancetype)retain
{
    return _instance;
}
//Set reference count to maximum (custom)
-(NSUInteger)retainCount
{
    return MAXFLOAT;
}
3. Singleton code applicable in both ARC and MRC environments

Use conditional compilation to determine whether ARC or MRC environments
On the basis of ARC code, conditional compilation is used to determine whether or not to override the following methods.

/*ARC Code snippet, see above*/

#if __has_feature(objc_arc) //If it is an ARC environment, no override is required
#else //If it is an MRC environment, rewrite the following code
-(oneway void)release{}
-(instancetype)retain{
    return _instance;
}
-(NSUInteger)retainCount{
    return MAXFLOAT;
}
#endif
4. Single-case codes that can be used by multiple classes (both ARC and MRC environments apply)

Create the file Single.h (file name is not fixed) and pull out a macro from the above code as follows:

/*
1 To replace characters after a macro definition, use##Stitching
2 If a line break occurs after the macro definition, the symbol " \ " To mark the next line as part of the macro definition, but not at the end of the last line
*/
//.h file   ##Represents stitching characters
#define SingleH(name) +(instancetype)share##name;

#if __has_feature(objc_arc) //Condition satisfies ARC
#define SingleM(name) static id _instance;\
+(instancetype)allocWithZone:(struct _NSZone *)zone{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instance = [super allocWithZone:zone];\
});\
return _instance;\
}\
+(instancetype)share##name{\
return [[self alloc]init];\
}\
-(id)copyWithZone:(NSZone *)zone{\
return _instance;\
}\
-(id)mutableCopyWithZone:(NSZone *)zone{\
return _instance;\
}

#else //MRC
#define SingleM(name) static id _instance;\
+(instancetype)allocWithZone:(struct _NSZone *)zone{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instance = [super allocWithZone:zone];\
});\
return _instance;\
}\
+(instancetype)share##name{\
return [[self alloc]init];\
}\
-(id)copyWithZone:(NSZone *)zone{\
return _instance;\
}\
-(id)mutableCopyWithZone:(NSZone *)zone{\
return _instance;\
}\
-(oneway void)release{}\
-(instancetype)retain{\
    return _instance;\
}\
-(NSUInteger)retainCount{\
    return MAXFLOAT;\
}
#endif

Suppose we want to use it in the class Person, the call method is as follows:
1. Import the file Singel.h into the project.
2. Code in Person class

Person.h file
===========================
#import <Foundation/Foundation.h>
#import "Single.h"
@interface Person
SingleH(Person)
@end

Person.m file
===========================
#import "Person.h"
@implementation Person.h
SingleM(Person)
@end

Be careful:

Inheritance is not allowed in singleton mode because it also inherits static variables, creating only one instance object created first when both the child and parent classes are created at the same time.

Posted by simplyi on Sun, 30 Jun 2019 12:26:47 -0700