# Series :iOS Development – singleton pattern

When we do development, we often encounter the phenomenon that we need to call the same object in many places. For example, in a class, we may use a global variable, and in a method, we may use a local variable repeatedly.

Today’s singleton pattern is one such existence

  1. The function of singleton mode: it can ensure that there is only one instance of a class in the running process of the program, and the instance is easy to be accessed by the outside world, so as to conveniently control the number of instances and save system resources.
  2. Where the singleton pattern can be used: Sharing a resource (which only needs to be created and initialized once) throughout the application should always create only one object from this class. That is, once you create a singleton class, no matter how many interfaces you initialize and call the singleton method to retrieve objects, all of them point to the same block of memory storage (that is, the singleton class guarantees that the power object of the class is the only one that exists).

The singleton pattern is one of the most commonly used design patterns in iOS development. The singleton pattern effectively solves the problem of sharing data between different codes without passing any parameters. Singleton classes are an important concept because they represent a very useful design pattern. Singletons are used throughout the iOS SDK. For example, the UIApplication class has a method called sharedApplication that, when called from anywhere, returns the UIApplication instance associated with the currently running application. In addition to this, NSNotificationCenter, NSFileManager, NSUserDefaults , NSURLCache(request cache), and NSHTTPCookieStorage(pool of application cookies) are system singletons;

In summary, a singleton class ensures that there is only one instance object of the class in the application’s life cycle and that it is easily accessible to the outside world.

So let’s see what his design idea should be.

  1. Only one block of memory is always allocated to create objects
  2. Provides a class method that returns a unique internal variable
  3. It’s good to make sure that init only initializes once because that’s the only way to make sure that whenever you create an object of this class, it’s going to be a fixed object

OK, now that we have an idea, how do we create it? Let’s first look at the init method of a normal class

- (instancetype)init{
    self = [super init];
    return self;
}
Copy the code

But this is an instance method, so we need to change it to a class method, so we create a method like this

static DemoSingleton *_instance = nil;
+(DemoSingleton *)shareDemoSingleton{
    if (_instance == nil) {
        _instance = [[self alloc]init];
    }
    return _instance;
}
Copy the code

Define a global variable first, then make a determination in the creation method, if there is a direct return, not create after return, this is a valid singleton creation pattern. Let’s print it out

But one of the things that might come to mind for those of you who have studied concurrency is, what if you didn’t have it at first, and then you had two places created at the same time? Yes, this will result in creating two different objects, which will not hit the desired effect for so long, so we have a new method, we add a lock

+(DemoSingleton *)shareDemoSingleton{
    NSLock *lock = [[NSLock alloc]init];
    [lock lock];
    if (_instance == nil) {
        _instance = [[self alloc]init];
    }
    [lock unlock];
    return _instance;
}
Copy the code

or

static DemoSingleton *instance = nil;
+(DemoSingleton *)shareDemoSingleton{
    @synchronized (self) {
        if (_instance == nil) {
            _instance = [[self alloc]init];
        }
        return_instance; }}Copy the code

Of course, we will learn about GCD in iOS later, and we can use this method as well

static DemoSingleton *_instance = nil;
+(DemoSingleton *)shareDemoSingleton{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc]init];
    });
    return _instance;
}
Copy the code

For each class,iOS itself provides a class method to create +(instancetype)allocWithZone:(struct _NSZone *)zone

So we need to write the same code here for rigor

+(instancetype)allocWithZone:(struct _NSZone *)zone{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [super allocWithZone:zone];
    });
    return _instance;
}
Copy the code

Not only that, we have copyWithZone and mutable with zone that we need to modify

-(id)copyWithZone:(NSZone *)zone
{
    return _instance;
}
-(id)mutableCopyWithZone:(NSZone *)zone
{
    return _instance;
}
Copy the code

But do we need to be this complicated every time we create a singleton? We could write a macro,

// @interface
#define singleton_interface(className) \
+ (instancetype)shared##className;


// @implementation
#define singleton_implementation(className) \
static className *_instance; \
+ (instancetype)shared##className \{ \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ _instance = [[self alloc] init]; The \}); \return_instance; \ } \ + (instancetype)allocWithZone:(NSZone *)zone \ { \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ _instance = [super allocWithZone:zone]; The \}); \return _instance; \
} \
- (instancetype)copyWithZone:(NSZone *)zone{ \
return _instance; \
} \
- (instancetype)mutableCopyWithZone:(NSZone *)zone{ \
return_instance; The \}Copy the code

Looks a little complicated?

OK, let’s import the dot h file, just two lines, and we’re done. Let’s do the same

OK, so that’s singletons, so what does singletons do? For a simple example, let’s say I’m developing music player software. What I can think of is I’ll create a music player class that has several methods, such as play, pause, fast forward, up and down, etc. I also have to make sure that I only have one player for the entire application, so whenever I call a player method anywhere in the entire application, I have to make sure THAT I’m operating on that unique player, otherwise I’ll have a problem. At this point, it would be good for me to use the singleton pattern. The player class is written as a singleton, so that wherever it is created, retrieved, copied, etc., it is always the same player that is being used…

Of course, if I have a lot of information data that needs to exist in the entire application, is also unique, such as user information, I can also write a singleton, easy to call anywhere,(of course, can also write to the database or sandbox, or other ways…).

IOS in development, provide us with a few own singleton, don’t think it has no effect, such as NSUserDefaults, persistence will ensure that the only requirement is that we do write in one place, and read it must have been made in that place, otherwise it won’t be able to read, have written a singleton, the requirement of itself actually is rather unique.

OK, singletons are just a design pattern, not complex in itself, it is still a class, any processing is a normal class, but all methods operate on a unique object.

The Demo address: github.com/spicyShrimp…

Series: iOS development – preface + outline blog.csdn.net/spicyShrimp…