Singleton Design Pattern
define
It is a scheme to ensure that there is only one object created by a class from beginning to end
role
- Save memory overhead
- Ensure that the same resource is used throughout the program
implementation
First, set our environment to a non-ARC environment, namely MRC, as shown
In MRC mode, we had to manually release resources ourselves, so we had to rewrite some of the methods associated with resource creation and release to keep singletons unique.
Create a new class LXFFileTool that inherits from NSObject, and I’ll just go to the code and comment LXFFileTool
@interface LXFFileTool : NSObject
+ (instancetype)sharedFileTool;
@end
Copy the code
LXFFileTool.m
#import "LXFFileTool.h"
@implementation LXFFileTool
static LXFFileTool *_fileTools = nil;
/** * The alloc method internally calls allocWithZone: * @param zone The memory allocated by the system to app */
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
if (_fileTools == nil) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ // Security (this code will only be called once)
_fileTools = [super allocWithZone:zone];
});
}
return _fileTools;
}
- (oneway void)release {
// GCD is used in allocWithZone so that the code to create the object is executed only once and cannot be created if _fileTools is released
// Override the release method to prevent _fileTools from being freed
}
// Override the retain method
- (instancetype)retain {
return self;
}
// Override retainCount to lock the reference count
- (NSUInteger)retainCount {
return 1;
}
// Override init to prevent property values owned by singletons from being reset
// Let the initialized method be executed only once, so that the natural property value has no chance to be reset
- (instancetype)init {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_fileTools = [super init]; Init calls the alloc method first
});
return _fileTools;
}
// Mimics the system singleton creation, providing class methods
+ (instancetype)sharedFileTool {
// Since we've overridden init to make the singleton unique, we can just call init.
return [[self alloc] init];
}
@end
Copy the code
This is the case with MRC. Our goal is to create and initialize an object only once, without giving chance to free it or reinitialize it, thus ensuring that the object is unique.
Let’s take a look at how singletons are implemented in ARC. The difference between ARC and MRC is that in ARC we no longer need to manually release resources, which makes the code similar, as shown below.
#import "LXFFileTool.h"
@implementation LXFFileTool
static LXFFileTool *_fileTools = nil;
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
if (_fileTools == nil) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_fileTools = [super allocWithZone:zone];
});
}
return _fileTools;
}
- (instancetype)init {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_fileTools = [super init];
});
return _fileTools;
}
+ (instancetype)sharedFileTool {
return [[self alloc] init];
}
Copy the code
Batch creating singletons
Now we know how to create singletons under ARC and MRC respectively, but if we need multiple singletons in a project, can we just copy and paste the code and change it? That’s a lot of trouble. Can we create singletons quickly and easily? Yes, use macros
First, let’s talk a little bit about macros
- Use the #define keyword to define macros
- Macro definitions can only be single-line, not newline
Let’s discuss some confusion. You say macros are single lines, but the code to create a singleton is many lines. And how do we customize class method names (i.e., sharedXXX)? Ok, so let’s introduce two special symbols under macros
A special symbol for a macro
role | |
---|---|
\ | Used to translate line breaks, that is, mask line breaks |
# # | Join two adjacent tokens into a single token |
For more information about macro preprocessing commands, please refer to “C language preprocessing commands “.
In simple terms, \ is used to cancel line breaks, ## is used to connect, and we use ## to implement custom class method names
Create a header file called singleton. h to hold the macro definition
// The implementation of.h files
#define SingletonH(methodName) + (instancetype)shared##methodName;
Copy the code
Now go back to LXFFileTool. H and define the sharedFileTool class method on a single line
#import "Singleton.h"
@interface LXFFileTool : NSObject
SingletonH(FileTool)
@end
Copy the code
We simply pass the method name FileTool into SingletonH() to spline it into sharedFileTool
Now let’s look at the way we create singletons in.m, using ARC as an example
#define SingletonM(methodName) \
static id _instance = nil; \
+ (instancetype)allocWithZone:(struct _NSZone *)zAone { \
if (_instance == nil) {\static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [superallocWithZone:zone]; The \}); \} \return_instance; \} \ \ - (instancetype)init { \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [superinit]; The \}); \return_instance; \} \ \ + (instancetype)shared##methodName { \
return [[selfalloc] init]; The \}Copy the code
Unwrap each line with a (backslash) and use ## to concatenate the method name passed in, but there is one more thing to note: the last line cannot be followed by a backslash
Back in LXFFileTool. M, a single line creates a singleton
#import "LXFFileTool.h"
@implementation LXFFileTool
SingletonM(FileTool)
@end
Copy the code
Ok, one more question is, if THERE are individual files in my project that require the MRC environment, how can I make it so easy to create singletons? It is very simple, just add a judgment, the general judgment is as follows, see the attached Demo at the end of the article for details
#if __has_feature(objc_arc) // ARC
// Write the ARC definition code
# else / / than the ARC
// Write the definition code under MRC
#endif
Copy the code
Ok, is it easier to use now? We simply create a class and write SingletonH(XXX) in the.h file and SingletonM(XXX) in the.m file to implement the singleton ~
Specify the environment
By the way, how do YOU specify ARC for a class file under MRC
-fobjc-arc
Copy the code
If MRC is specified
-fno-objc-arc
Copy the code
Demo
Finally, I attach the Demo: LXFSingleton