昨天总结了swift的单例创建模式,今天总结一下OC单例的创建模式
单例用处:主要用在封装网络请求,播放器,存放常用数据。
单例特点:只初始化一次,生命和程序的生命周期相同,访问方便。
创建单例最初的学习到的写法是判断对象是否为空,为空才创建,但这仅仅是单线程安全,为了多线程安全,创建单例时会加锁,写法如下
+ (instancetype)shareManager{
@synchronized(self){
if (!manager) {
manager = [[self alloc]init];
}
return manager;
}
}
后来发现GCD创建单例更加简便
static DataManager *manager = nil;
@implementation DataManager
+ (instancetype)shareManager{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[self alloc] init];
});
return manager;
}
@end
此时单例就已经写好了,只要我们在外面调用shareManager这个方法,返回的对象始终是一个,因为dispatch_once只执行一次。
1、如果不小心调用了alloc、allocWithZone方法呢?此时的manager还是同一个对象吗?
答案:当然不是。
解决方法:参考从 Objective-C 里的 Alloc 和 AllocWithZone 谈起这篇文章加上事件证明,发现调用alloc
方法时,会自动调用allocWithZone
方法,此时只需要重写AllocWithZone
即可。
+ (id)allocWithZone:(struct _NSZone *)zone{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [super allocWithZone:zone];
});
return manager;
}
此时的DataManager.m
代码如下
#import "DataManager.h"
@interface DataManager()
@end
static DataManager *manager = nil;
@implementation DataManager
+ (instancetype)shareManager{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[self alloc]init];
});
return manager;
}
+ (id)allocWithZone:(struct _NSZone *)zone{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [super allocWithZone:zone];
});
return manager;
}
@end
2、如果不小心调用了copy、mutableCopy方法呢?此时还是同一个对象吗?
答案:运行崩溃。
崩溃原因:提示[DataManager copyWithZone:]: unrecognized selector sent to instance 0x600003b71710'
,因为对应自己定义的类,要实现copy
就要默认实现NSCopying
协议,同理实现mutablecopy
就要实现NSMutableCopying
协议。
解决办法:那就实现NSCopying的方法- (id)copyWithZone:(nullable NSZone *)zone;
和NSMutableCopying的方法- (id)mutableCopyWithZone:(nullable NSZone *)zone;
因为要保持manager
始终是一个单例,此时直接返回已经初始化的对象。
此时的DataManager.m代码如下
#import "DataManager.h"
@interface DataManager()
@end
static DataManager *manager = nil;
@implementation DataManager
+ (instancetype)shareManager{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[self alloc]init];
});
return manager;
}
+ (id)allocWithZone:(struct _NSZone *)zone{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [super allocWithZone:zone];
});
return manager;
}
- (nonnull id)copyWithZone:(nullable NSZone *)zone {
return manager;
}
- (nonnull id)mutableCopyWithZone:(nullable NSZone *)zone {
return manager;
}
@end
到此一个完整的单例创建就完成啦~~~
当然也有别的方法实现,就是在shareManager
方法里面,不添加dispatch_once
,这样子每调用一次[DataManager shareManager]
就会执行一次init
,那此时init
方法需要使用dispatch_once
,避免多次进行初始化,代码如下:
#import "DataManager.h"
@interface DataManager()
@end
static DataManager *manager = nil;
@implementation DataManager
+ (instancetype)shareManager{
return [[self alloc] init];
}
- (instancetype)init{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [super init];
});
return manager;
}
+ (id)allocWithZone:(struct _NSZone *)zone{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [super allocWithZone:zone];
});
return manager;
}
- (nonnull id)copyWithZone:(nullable NSZone *)zone {
return manager;
}
- (nonnull id)mutableCopyWithZone:(nullable NSZone *)zone {
return manager;
}
最后,我还是推崇第一种方式,调用shareManager方法时,看到使用了dispatch_once,就知道这是个单例啦,很多大牛的三方,都是用的第一种方式勒~
参考地址:
iOS-单例模式写一次就够了
iOS开发多线程篇—单例模式
从 Objective-C 里的 Alloc 和 AllocWithZone 谈起
Objective-C copy,看我就够了
喜欢就点个赞吧✌️✌️
有错之处,还请指出,感谢