How the singleton pattern is defined may not be exactly the same in different languages and in different books, but the general situation should be that there is only one instance of a class, and that it is provided to the system as a self-instantiation.
So, first you might want to make sure that you really need a singleton class, or simply an instantiation method that calls for convenience. If you really need a singleton class, then you should make sure that the Singleton class has and only one instance (you can only get to this instance for any operation).
Recently saw some of the singleton use on GitHub, other people's usage, have some thinking, and then write the demo test, there are some pits on this simple singleton, hoping to give others some reminders.
Objective-c in a single case
We typically implement a single case approach in OC:
static HLTestObject *instance = nil;+ (instancetype)sharedInstance{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [[[self class] alloc] init]; }); return instance;}
But is that okay? I did the following tests:
HLTestObject *objct1 = [HLTestObject sharedInstance];NSLog(@"%@",objct1);HLTestObject *objc2 = [[HLTestObject alloc] init];NSLog(@"%@",objc2);HLTestObject *objc3 = [HLTestObject new];NSLog(@"%@",objc3);
See this test, do you want to print the results? The result is this:
2016-05-23 12:52:57.095 PractiseProject[3579:81998] 2016-05-23 12:52:57.095 PractiseProject[3579:81998] 2016-05-23 12:52:57.095 PractiseProject[3579:81998]
Obviously, there are different instance objects created in three ways, which violates the definition of a singleton class with only one instance.
To prevent others from accidentally using Alloc/init to create an example, and to prevent others from deliberately doing it, we want to make sure that no matter how it is created can only be the same instance object, it is necessary to rewrite another method, implemented as follows:
+ (instancetype)allocWithZone:(struct _NSZone *)zone{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [super allocWithZone:zone]; }); return instance;}
Again with the test code above, the result is this:
2016-05-23 12:57:37.396 PractiseProject[3618:83975] 2016-05-23 12:57:37.396 PractiseProject[3618:83975] 2016-05-23 12:57:37.396 PractiseProject[3618:83975]
It seems that the same object is obtained with different construction methods, do you think it's over? It's still early!
In general our class will definitely have some properties, then I added two properties:
@property (assign, nonatomic) int height;@property (strong, nonatomic) NSObject *object;@property (strong, nonatomic) NSMutableArray *arrayM;
Some object classes are initialized, or the default value of the underlying type is set in the Init method, like this:
- (instancetype)init{ self = [super init]; if (self) { _height = 10; _object = [[NSObject alloc] init]; _arrayM = [[NSMutableArray alloc] init]; } return self;}
I rewrote the description method of the Hltestobject class:
- (NSString *)description{ NSString *result = @""; result = [result stringByAppendingFormat:@"<%@: %p>",[self class], self]; result = [result stringByAppendingFormat:@" height = %d,",self.height]; result = [result stringByAppendingFormat:@" arrayM = %p,",self.arrayM]; result = [result stringByAppendingFormat:@" object = %p,",self.object]; return result;}
Or with the test code above, the test result is this:
2016-05-23 13:14:43.684 PractiseProject[3781:92758] height = 20, arrayM = 0x7f8a5b422940, object = 0x7f8a5b4544e0,2016-05-23 13:14:43.684 PractiseProject[3781:92758] height = 10, arrayM = 0x7f8a5b4552e0, object = 0x7f8a5b45a710, 2016-05-23 13:14:43.684 PractiseProject[3781:92758] height = 10, arrayM = 0x7f8a5b459770, object = 0x7f8a5b4544e0,
As you can see, although the same example is used, their property values are different.
Because although no memory space is reallocated for the example, the Init method is executed, which causes the property to be reinitialized.
So we need to change the implementation of the Singleton.
The first type:
You can put the property's initialization or default value settings inside the Dispatch_once block:
static hltestobject *instance = nil;+ (instancetype) sharedInstance{static dispatch_once_t Oncetoken; Dispatch_once (&oncetoken, ^{instance = [[[Self class] alloc] init]; Instance.height = 10; Instance.object = [[NSObject alloc] init]; Instance.arraym = [[Nsmutablearray alloc] init]; }); return instance;} + (Instancetype) Allocwithzone: (struct _nszone *) zone{static dispatch_once_t Oncetoken; Dispatch_once (&oncetoken, ^{instance = [Super Allocwithzone:zone]; }); return instance;} -(NSString *) description{nsstring *result = @ ""; result = [Result stringbyappendingformat:@ "<%@:%p>", [Self class], self]; result = [result stringbyappendingformat:@ "height =%d,", self.height]; result = [result stringbyappendingformat:@ "Arraym =%p,", Self.arraym]; result = [Result stringbyappendingformat:@ "object =%p,", Self.object]; return result;}
Take a look at the test results:
2016-05-23 13:29:14.856 PractiseProject[3909:99058] height = 20, arrayM = 0x7fa722716c10, object = 0x7fa7227140e0,2016-05-23 13:29:14.856 PractiseProject[3909:99058] height = 20, arrayM = 0x7fa722716c10, object = 0x7fa7227140e0, 2016-05-23 13:29:14.856 PractiseProject[3909:99058] height = 20, arrayM = 0x7fa722716c10, object = 0x7fa7227140e0,
The second type:
static Hltestobject *instance = nil;+ (instancetype) sharedinstance{return [[Self alloc] init];} -(instancetype) init{static dispatch_once_t Oncetoken; Dispatch_once (&oncetoken, ^{instance = [Super init]; Instance.height = 10; Instance.object = [[NSObject alloc] init]; Instance.arraym = [[Nsmutablearray alloc] init]; }); return instance;} + (Instancetype) Allocwithzone: (struct _nszone *) zone{static dispatch_once_t Oncetoken; Dispatch_once (&oncetoken, ^{instance = [Super Allocwithzone:zone]; }); return instance;} -(NSString *) description{nsstring *result = @ ""; result = [Result stringbyappendingformat:@ "<%@:%p>", [Self class], self]; result = [result stringbyappendingformat:@ "height =%d,", self.height]; result = [result stringbyappendingformat:@ "Arraym =%p,", Self.arraym]; result = [Result stringbyappendingformat:@ "object =%p,", Self.object]; return result;}
Test results:
2016-05-23 13:31:44.824 PractiseProject[3939:100662] height = 20, arrayM = 0x7fa9da707ca0, object = 0x7fa9da70a940,2016-05-23 13:31:44.825 PractiseProject[3939:100662] height = 20, arrayM = 0x7fa9da707ca0, object = 0x7fa9da70a940, 2016-05-23 13:31:44.825 PractiseProject[3939:100662] height = 20, arrayM = 0x7fa9da707ca0, object = 0x7fa9da70a940,
Attention:
The above code uses ARC to manage memory, if you are still using MRC (which is too much to keep up with the times). You also need to rewrite the retain and release methods to prevent changes to the sample reference count.
A single case in Swift
Using some of the features in Swift, the singleton in Swift can be super simple, like this:
class HLTestObject: NSObject { static let sharedInstance = HLTestObject();}
But that's it? Also write a test code:
let object1 = HLTestObject.sharedInstance;print(object1);let object2 = HLTestObject();print(object2);
The printing result is this:
Therefore, we must disable to the constructor method:
class HLTestObject: NSObject { static let sharedInstance = HLTestObject(); private override init() { }}
If you have an instance property that needs to be initialized, you can:
class HLTestObject: NSObject { var height = 10; var arrayM: NSMutableArray var object: NSObject static let sharedInstance = HLTestObject(); private override init() { object = NSObject() arrayM = NSMutableArray() super.init() }}
Of course, because of Swift's nature, there is more than one way to create a singleton in Swift, and it is important to ensure that the class has and only one instance is OK.
Have fun!
A singleton in iOS