1: the concept of
Singletons are a common design pattern. The singleton mode can ensure that a class in the system has only one instance and the instance is easy to access, so as to facilitate the control of the number of instances and save system resources.
There is only one instance of a singleton in its class and, like a global variable, it can be accessed anywhere in the system.
2: use
1) Only one object can exist in the system.
2) Only one instance of an object in the system is enough to save memory.
3: Some use of singletons in iOS
[UIApplication sharedApplication];
[NSNotificationCenter defaultCenter];
[NSFileManager defaultManager];
[NSUserDefaults standardUserDefaults];
[NSURLCache sharedURLCache];
[NSHTTPCookieStorage sharedHTTPCookieStorage];Copy the code
Creating an iOS singleton
1. Single thread singleton
We know that for a singleton class, we have to set aside an interface to return the generated singleton. Since there can only be one instance in a class, we create the instance the first time we access it, and then access it directly from the already created instance
@implementation Singleton
+ (instancetype)shareInstance
{
static Singleton* single;
if(! single) { single = [[Singleton alloc] init]; }return single;
}
@end
Copy the code
Ps: Strictly speaking, we also need to seal the alloc method, because strict singletons are not allowed to create other instances, and the Alloc method can generate arbitrary instances externally. But given that alloc is an NSObject, there’s no way to make alloc private in iOS. The best you can do is to overwrite the alloc and let it return null, which can lead to other problems for people using the interface. So normally we don’t do anything special with alloc. The singleton of the system also does nothing to alloc
2. @ synchronized singleton
We generally can’t guarantee that an instance will be used in single-threaded mode, so we have to accommodate multithreading. The above singleton creation approach can be problematic in multithreaded situations. If two threads call shareInstance at the same time, it is possible to create two singles. So in multithreaded cases, we need to use @synchronized to lock.
@implementation Singleton
+ (instancetype)shareInstance
{
static Singleton* single;
@synchronized(self) {if (!single) {
single = [[Singleton alloc] init];
}
}
return single;
}
@end
Copy the code
That way, when multiple threads call shareInstance at the same time, only one thread can enter to create a single because @synchronized is already locked. In this way, the problem of multithreading call singleton is solved
3. Dispatch_once singleton
Using @synchronized solves the multithreading problem, but it’s not perfect. The lock is only necessary if the single is not created. If single is already created. Not only is locking not beneficial, it also affects the performance of program execution (when multiple threads execute code in @synchronized, only one thread executes and the others wait). So is there a way to solve the problem without affecting performance? This method is dispatch_once in GCD
@implementation Singleton
+ (instancetype)shareInstance
{
static Singleton* single;
static dispatch_once_t onceToken; / / onceToken = 0;
dispatch_once(&onceToken, ^{
NSLog(@"%ld",onceToken); / / (2) onceToken = 140734731430192
single = [[Singleton alloc] init];
});
NSLog(@"%ld",onceToken); / / (3) onceToken = 1;
return single;
}
@end
Copy the code
How can dispatch_once solve simultaneous multithreading problems without affecting performance? Here’s how dispatch_once works:
Dispatch_once determines how to execute code based on the onceToken value.
- when
onceToken
= 0, the thread executesdispatch_once
theblock
In the code - when
onceToken
If = -1, the thread skipsdispatch_once
theblock
Code is not executed in - when
onceToken
For other values, the thread is blocked by the thread, waitingonceToken
Values change
When a thread calls shareInstance first and executes the code in the block, it first needs to change the value of onceToken before executing the code in the block. Here the onceToken value changes to 140734731430192. When another thread retrieves the value of onceToken, the value will already be 140734731430192. Other threads are blocked. When the block thread finishes executing the block. The onceToken changes to -1. Other threads stop blocking and skip the block. The next time shareInstance is called, block will already be -1. Skip the block. In this way, dispatch_once synchronizes the blocking thread on the first call and does not block the thread after the singleton is generated. Dispatch_once is the optimal solution for creating singletons
Conclusion:
- The singleton is a good design pattern that acts like a global variable, allowing us to use the same instance everywhere.
- If you want to create your own singleton pattern, it is best to use it
dispatch_once
Method, so as to solve the problem of multi-threading, and can achieve the purpose of efficient
While singletons are useful, they do not lend themselves well to inheritance and extension, so be careful when using them. Don’t use singletons for everything, just enough