昨天总结了swift的单例创建模式,今天总结一下OC单例的创建模式,本人才疏学浅,如有错误之处,还望大家指出。
创建单例最初的学习到的写法是判断对象是否为空,为空才创建,但这仅仅是单线程安全,为了多线程安全,创建单例时会加锁,写法如下
+ (instancetype)shareManager{
@synchronized(self){
if (!manager) {
manager = [[DataManager alloc]init];
}
return manager;
}
}
后来发现GCD创建单例更加简便
static DataManager *manager = nil;
@implementation DataManager
+ (instancetype)shareManager{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[DataManager alloc] init];
// [[super allocWithZone:nil] init]; 在某些博客说如果重写allocWithZone方法,此时调用[[DataManager alloc] init]会导致死循环,尝试后发现,没有出现这种情况。
});
return manager;
}
@end
此时单例就已经写好了,只要我们在外面调用shareManager这个方法,返回的对象始终是一个,因为dispatch_once只执行一次。
但是如果我们不小心调用了alloc、copy、mutablecopy(因为本文的DataManager继承自NSObject,默认DataManager实现了NSCopying,NSMutableCopying协议,否则copy、mutablecopy会导致崩溃) 返回的对象就不是同一个了,因为这些操作会生成新的对象,要保证单例的唯一性就需要重写这些方法。
+ (instancetype)alloc{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[super alloc]init];
NSLog(@"allocWithZone----");
});
return manager;
}
- (nonnull id)copyWithZone:(nullable NSZone *)zone {
// return self; 此处返回self或者manager 打印的对象是同一个,并没有发现什么区别
return manager;
}
- (nonnull id)mutableCopyWithZone:(nullable NSZone *)zone {
// return self; 此处返回self或者manager 打印的对象是同一个,并没有发现什么区别
return manager;
}
又发现有的博客中提到了重写allocWithZone,查询资料后发现,我们调用alloc方法系统最终会调用allocWithZone,所以重写alloc 或者allocWithZone基本上是一样的。NSZone是Apple用来分配和释放内存的一种方式,alloc 和allocWithZone 的区别,在下面我给出参考博客的地址。
+ (id)allocWithZone:(struct _NSZone *)zone{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [super allocWithZone:zone];
NSLog(@"allocWithZone----");
});
return manager;
}
到此ARC机制下的单例创建就完成了,单例主要用在封装网络请求,播放器,存放常用数据,单例只初始化一次,整个APP随处可以访问,使用方便。
期间参考了很多地址,如有遗漏,还请见谅。
参考地址:
iOS-单例模式写一次就够了
iOS开发多线程篇—单例模式
从 Objective-C 里的 Alloc 和 AllocWithZone 谈起
Objective-C copy,看我就够了
网友评论