单例是 iOS 设计模式之一
1、大家一般都会这么写
#import "Singleton.h"
@implementation Singleton
+ (instancetype)sharedInstance
{
static Singleton *singleton = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singleton = [[self alloc] init];
});
return singleton;
}
一般情况下,初始化一个类 会使用 init,假如使用 init 创建,是否还是只有一个实例
NSLog(@"1: %p",[Singleton sharedInstance]);
NSLog(@"2: %p",[Singleton sharedInstance]);
NSLog(@"3: %p",[[Singleton alloc] init]);
NSLog(@"4: %p",[[Singleton alloc] init]);
1: 0x600002d5b950
2: 0x600002d5b950
3: 0x600002d642e0
4: 0x600002d60060
1 和 2 是一样的,但是和 3 与 4 都不一样
所以这样写是不完善的
2、改善一下
+ (instancetype)sharedInstance
{
static Singleton *singleton = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singleton = [[super allocWithZone:NULL] init];
});
return singleton;
}
+ (id)allocWithZone:(struct _NSZone *)zone
{
return [self sharedInstance];
}
再次打印,得到结果
2019-05-27 01:41:22.327625+0800 test001[44286:3651397] 1: 0x60000242c230
2019-05-27 01:41:22.327686+0800 test001[44286:3651397] 2: 0x60000242c230
2019-05-27 01:41:22.327802+0800 test001[44286:3651397] 3: 0x60000242c230
2019-05-27 01:41:22.327922+0800 test001[44286:3651397] 4: 0x60000242c230
得到的都是同一个对象
使用 init 方法时,每次都会调用 init ,都会执行 init 方法
Singleton init 方法
- (instancetype)init
{
self = [super init];
if (self) {
NSLog(@"init");
}
return self;
}
NSLog(@"5: %p",[[Singleton alloc] init]);
NSLog(@"6: %p",[[Singleton alloc] init]);
NSLog(@"7: %p",[[Singleton alloc] init]);
NSLog(@"8: %p",[[Singleton alloc] init]);
// 打印结果
2019-05-27 01:51:40.563060+0800 test001[44465:3684646] init
2019-05-27 01:51:40.563114+0800 test001[44465:3684646] 5: 0x600001cf8e30
2019-05-27 01:51:40.563172+0800 test001[44465:3684646] init
2019-05-27 01:51:40.563223+0800 test001[44465:3684646] 6: 0x600001cf8e30
2019-05-27 01:51:40.563272+0800 test001[44465:3684646] init
2019-05-27 01:51:40.563320+0800 test001[44465:3684646] 7: 0x600001cf8e30
2019-05-27 01:51:40.563440+0800 test001[44465:3684646] init
2019-05-27 01:51:40.563543+0800 test001[44465:3684646] 8: 0x600001cf8e30
每次都会调用 init 方法
- (instancetype)init
{
if (singleton != nil)
return self;
self = [super init];
if (self) {
NSLog(@"init");
}
return self;
}
这样处理后,不管怎样,都只会调用一次 init,每次得到的对象也同一个对象
测试一下
#import "Singleton.h"
static Singleton *singleton = nil;
@implementation Singleton
- (instancetype)init
{
if (singleton != nil)
return self;
self = [super init];
if (self) {
NSLog(@"init");
}
return self;
}
+ (instancetype)sharedInstance
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singleton = [[super allocWithZone:NULL] init];
});
return singleton;
}
+ (id)allocWithZone:(struct _NSZone *)zone
{
return [self sharedInstance];
}
// 在其他文件中,使用这个单例
Singleton *s1 = [Singleton sharedInstance];
s1.name = @"001";
Singleton *s2 = [Singleton sharedInstance];
NSLog(@"A: %@",s2.name);
s2.name = @"002";
Singleton *s3 = [[Singleton alloc] init];
NSLog(@"B: %@",s3.name);
s3.name = @"003";
Singleton *s4 = [[Singleton alloc] init];
NSLog(@"C: %@",s4.name);
// 打印结果
2019-05-27 01:56:31.034039+0800 test001[44526:3700399] init
2019-05-27 01:56:31.034143+0800 test001[44526:3700399] A: 001
2019-05-27 01:56:31.034237+0800 test001[44526:3700399] B: 002
2019-05-27 01:56:31.034436+0800 test001[44526:3700399] C: 003
单例另一种写法
+ (instancetype)sharedInstance
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singleton = [[Singleton alloc] init];
});
return singleton;
}
// 使用 alloc 方法初始化一个类的实例的时候,默认是调用了 allocWithZone 的方法
+ (id)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singleton = [super allocWithZone:zone];
});
return singleton;
}
// 测试如下
NSLog(@"\n%p\n%p",[Singleton sharedInstance],[Singleton sharedInstance]);
NSLog(@"\n%p\n%p",[[Singleton alloc] init],[[Singleton alloc] init]);
得到四个指针地址是一样的