A singleton design pattern is often used in development to create only instance objects of a class for the entire life of a program, and the instance object will not be freed as long as the program is not killed. Let's look at the concepts, uses, and how to create a singleton to deepen our understanding.
Role
When you apply this pattern, the class of the Singleton object must guarantee that only one instance exists. Many times the entire system needs to have only one global object, which helps us coordinate the overall behavior of the system. For example, in app development we may use the user's information anywhere, then you can log in the user information in a file, the configuration data is read by a singleton object, and then the other objects in the service process through the Singleton object to obtain these configuration information. This approach simplifies configuration management in complex environments.
In some cases, a class may have only one instance. For example, if you write a class to play music, then you can only have one instance of that class to play the sound at any time. For example, a computer can be connected to several printers, but the printer on this computer can only have one, here you can use a singleton mode to avoid the simultaneous output of two print tasks to the printer, that is, throughout the printing process I have only one instance of the print program.
Create a single case
There are two ways to create a singleton, each of which describes
1, GCD way to create a single case
| 123456789101112131415161718192021222324 |
static id _instance;+ (instancetype)allocWithZone:(struct _NSZone *)zone{static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{_instance = [superallocWithZone:zone];});return_instance;}+ (instancetype)sharedInstance{static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{_instance = [[self alloc] init];});return_instance;}- (id)copyWithZone:(NSZone *)zone{return_instance;}- (id)mutableCopyWithZone:(NSZone *)zone {return_instance;} |
2, mutual exclusion lock mode
| 1234567891011121314151617181920212223 |
static id _instance;+ (instancetype)allocWithZone:(struct _NSZone *)zone{@synchronized(self) {if(_instance == nil) {_instance = [superallocWithZone:zone];}}return_instance;}+ (instancetype)sharedInstance{@synchronized(self) {if(_instance == nil) {_instance = [[self alloc] init];}}return_instance;}- (id)copyWithZone:(NSZone *)zone{return_instance;} |
The above two ways can create a singleton, and ensure that the user either through the Shareinstance method, or the Alloc, copy method to get the same instance.
The key point of the above code is how to guarantee the creation of the singleton or the same one in multithreaded situations.
Let's take a look at the GCD case, if you don't use dispatch_once and sync locks to create a single-session problem, remove the two and create a singleton code as follows
| 123456 |
+ (instancetype)sharedInstance{if(_instance == nil) {_instance = [[self alloc] init];}} |
Assuming there are two threads at this time: Thread 1 and Thread 2, all calling the Shareinstance method to create the singleton, then thread 1 runs to if (_instance = = nil) out of the discovery _instance = nil, then initializes a _instance, Assuming that thread 2 is also running at the discretion of the IF, thread 1 has not yet created the completion instance _instance, so at this point _instance = nil or set, then thread 2 will create a _instace.
At this point, two instance objects are created, causing the problem.
Workaround 1, use Dispatch_once
Dispatch_once guarantee that the program will run only once, then assume that thread 1 executes the Shareinstance method first, create an instance object, thread 2 will no longer execute dispatch_once code. This ensures that only one instance object is created.
Workaround 2, use mutex lock
Assuming thread 1 is executing the Shareinstance method at this point, create a singleton code inside the synchronize brace, as follows:
| 123 |
if(_instance == nil) {_instance = [[self alloc] init];} |
will be treated as a task to be added a lock. At this point, assume that thread 2 also wants to execute the Shareinstance method to create a singleton, but see the thread 1 plus the mutex, will go into sleep mode. Wait until thread 1 is completed before it wakes up, then executes the code shown above to create the singleton, but at this point _instance!=nil, so no new instance objects are created. This ensures that only one instance object is created.
But mutexes can affect performance, so it's best to create a singleton using the GCD method.
Macro Create a single case
If we need to create more than one singleton in a program, it is tedious to write the above code once in each class.
We can use macros to encapsulate the creation of a singleton, so that any class needs to create a singleton, just one line of code to get it done.
Implementation code
| 1234567891011121314151617181920212223242526272829303132 |
Singleton.h文件==================================#define SingletonH(name) + (instancetype)shared##name;#define SingletonM(name) \static id _instance; \\+ (instancetype)allocWithZone:(struct _NSZone *)zone \{ \static dispatch_once_t onceToken; \dispatch_once(&onceToken, ^{ \_instance = [superallocWithZone:zone]; \}); \return_instance; \} \\+ (instancetype)shared##name \{ \static dispatch_once_t onceToken; \dispatch_once(&onceToken, ^{ \_instance = [[self alloc] init]; \}); \return_instance; \} \\- (id)copyWithZone:(NSZone *)zone \{ \return_instance; \}\\- (id)mutableCopyWithZone:(NSZone *)zone { \return_instance; \} |
How to Invoke
Suppose we want to use it in class Viewcontroller, call the following method:
| 123456789101112131415161718 |
viewcontroller.h文件===========================#import#import "Singleton.h"@interface ViewController : UIViewControllerSingletonH(viewController)@endviewcontroller.m文件===========================@interface ViewController ()@end@implementation ViewControllerSingletonM(ViewController)- (void)viewDidLoad {[superviewDidLoad];NSLog(@"%@ %@ %@ %@", [ViewController sharedViewController],[ViewController sharedViewController], [[ViewController alloc] init],[[ViewController alloc] init]);}@end |
Output results
iOS single-instance explanation