为什么80%的码农都做不了架构师?>>>
单例模式很常见,但是,能真正把单利模式写对的却很少。在iOS中,一般我们都是用官方推荐的写法来写单例:
+ (instancetype)sharedInstance {
static URLManager * ins = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
ins = [[URLManager alloc] init];
});
return ins;
}
这也是我们单例模式的标准写法。 在使用时,我们只需要
URLManager* a = [URLManager sharedInstance];
就可以用 a 这个单例来干很多事情了,看起来没有问题。在很多实际的项目中,很多人也的确是这么做的。
问题:
可是,在多人开发中,并不能保证所有人都会使用 sharedInstance 方法来创建对象;而一旦有人用 alloc,new 等来创建对象,这就不是单例了。例如:
URLManager* a = [URLManager sharedInstance];
URLManager* b = [[URLManager alloc] init];
URLManager* c = [URLManager new];
查看 a、b、c :
可以看到,a、b、c 不是同一个对象,而所谓单例,就是不管我用何种方法创建对象,都必须是同一个。所以,单例模式,绝不是一个 sharedInstance 就够了。
方案一、
那么如何避免这种问题呢?我们知道:在对象创建的时候,alloc、new都会调用到 allocWithZone: 方法;使用拷贝创建对象时,会调用 copyWithZone: 、mutableCopyWithZone:方法;那么,重写这些方法,就可以让创建的对象唯一。
+(id)allocWithZone:(NSZone *)zone{
return [self sharedInstance];
}
-(id)copyWithZone:(NSZone *)zone{
return [[self class] sharedInstance];
}
-(id)mutableCopyWithZone:(NSZone *)zone{
return [[self class] sharedInstance];
}
再运行,看一看a、b、c:
都是同一个对象!大功告成!
方案二、
此外,还有一种方法,就是直接禁用掉 alloc、new 、copy等方法:
+ (instancetype)sharedInstance;
+(instancetype) alloc __attribute__((unavailable("replace with 'sharedInstance'")));
+(instancetype) new __attribute__((unavailable("replace with 'sharedInstance'")));
-(instancetype) copy __attribute__((unavailable("replace with 'sharedInstance'")));
-(instancetype) mutableCopy __attribute__((unavailable("replace with 'sharedInstance'")));
+ (instancetype)sharedInstance {
static URLManager * ins = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
ins = [[super allocWithZone:nil] init];
});
return ins;
}
如此,在调用这些方法时就会报错,提示使用 sharedInstance 方法:
以此,也可以达到单例模式的要求,始终只有一个对象。