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.

  1. whenonceToken= 0, the thread executesdispatch_oncetheblockIn the code
  2. whenonceTokenIf = -1, the thread skipsdispatch_oncetheblockCode is not executed in
  3. whenonceTokenFor other values, the thread is blocked by the thread, waitingonceTokenValues 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:

  1. The singleton is a good design pattern that acts like a global variable, allowing us to use the same instance everywhere.
  2. If you want to create your own singleton pattern, it is best to use itdispatch_onceMethod, 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