注意:以下都是ARC模式下操作,如果不幸是MRC模式,也比较简单,只需要写上四个方法让MRC代码失效,即可覆盖四个方法:分别是
//只需要写上这几句让MRC代码失效即可
- (oneway void)release{
}
- (instancetype)retain{
return self;
}
- (NSUInteger)retainCount{
return 1;
}
- (instancetype)autorelease{
return self;
}
- 单例模式有两种:懒汉式和饿汉式
- 懒汉式是用到时再加载,饿汉式是程序启动加入内存的时候直接加载。
- 具体如何创建以及为什么这么创建在代码注释中可以清晰看到
- 其实都是重写三个方法:
- 第一个肯定是alloc方法,只分配一次内存
- 第二个是一个自定义的工厂模式的方法,我这里命名为sharedPlayer
- 第三个是copy方法,以防止有时候用copy操作
1,不使用GCD的情况下:
懒汉式:
#pragma mark- 懒汉式加载方式
//static修饰时为了防止外部用extern进行引用这个类然后意外修改_musicPlayer的值。
static id _musicPlayer;
//单例模式实际上就是需要保证内存只有一个,而内存是在alloc方法中分配的,所以只需要在alloc方法中进行限制即可
//调用alloc的时候实际上是调用这个方法,所以最好在这个方法内部进行单例初始化
+ (instancetype)allocWithZone:(struct _NSZone *)zone{
//判断是否需要加锁,如果需要,加上锁然后进行初始化,不然直接跳过,不必加锁,因为加锁比较消耗内存
if (_musicPlayer == nil) {
//如果前面什么都不判断,那么一进来就会加锁,加锁比较频繁,所以我们会在加锁之前先进行判断是否需要加锁
@synchronized (self) {
if(_musicPlayer == nil){
//注意:这里一定是调用父类的方法
_musicPlayer = [super allocWithZone:zone];
}
}
}
return _musicPlayer;
}
//一般建议写一个简便的全局方法进行初始化
//可以直接返回[[self alloc] init],但是这样虽然只会分配一次内存,但是每次仍然会初始化,不是最好,最好的方法如下
+ (instancetype)sharedPlayer{
//这里应该是不需要加锁的,因为本质上这个方法里面还是调用alloc方法,在alloc的内部方法中已经加过锁,是安全的,这里就没必要加锁
if (_musicPlayer == nil) {
_musicPlayer = [[self alloc] init];
}
return _musicPlayer;
}
//有时候需要copy,所以需要重写这个方法
- (id)copyWithZone:(NSZone *)zone{
//既然是拷贝,那么值钱必然已经创建过一次,所以可以直接返回这个全局变量即可
return _musicPlayer;
}
饿汉式:
#pragma mark- 饿汉式加载方式
//static修饰时为了防止外部用extern进行引用这个类然后意外修改_musicPlayer的值。
static id _musicPlayer;
+ (void)load{
//只会加载一次也就不需要加锁
_musicPlayer = [[super alloc] init];
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone{
//不需要加锁,因为除了load方法中调用alloc的时候_musicPlayer是空之外,其他的时候都是有值的,直接返回_musicPlayer的
if (_musicPlayer == nil) {
_musicPlayer = [super allocWithZone:zone];
}
return _musicPlayer;
}
//一般建议写一个简便的全局方法进行初始化
//可以直接返回[[self alloc] init],但是这样虽然只会分配一次内存,但是每次仍然会初始化,不是最好,最好的方法如下
+ (instancetype)sharedPlayer{
return _musicPlayer;
}
//有时候需要copy,所以需要重写这个方法
- (id)copyWithZone:(NSZone *)zone{
return _musicPlayer;
}
2,使用GCD的情况下:
- 其实就是把加锁判断的操作全部用dispatch_once方法进行修改就可以了
懒汉式:
#pragma mark- 使用GCD的懒汉式加载方式
//static修饰时为了防止外部用extern进行引用这个类然后意外修改_musicPlayer的值。
static id _musicPlayer;
//单例模式实际上就是需要保证内存只有一个,而内存是在alloc方法中分配的,所以只需要在alloc方法中进行限制即可
//调用alloc的时候实际上是调用这个方法,所以最好在这个方法内部进行单例初始化
+ (instancetype)allocWithZone:(struct _NSZone *)zone{
//因为GCD默认是加过锁的,是线程安全的,所以不需要再做任何加锁判断操作了
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_musicPlayer = [super allocWithZone:zone];
});
return _musicPlayer;
}
//一般建议写一个简便的全局方法进行初始化
//可以直接返回[[self alloc] init],但是这样虽然只会分配一次内存,但是每次仍然会初始化,不是最好,最好的方法如下
+ (instancetype)sharedPlayer{
//这里再调用一次GCD就OK了
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_musicPlayer = [[self alloc] init];
});
return _musicPlayer;
}
//有时候需要copy,所以需要重写这个方法
- (id)copyWithZone:(NSZone *)zone{
//既然是拷贝,那么值钱必然已经创建过一次,所以可以直接返回这个全局变量即可
return _musicPlayer;
}
饿汉式
- 由于饿汉式是在加载的时候已经分配好空间,之后没有必要加锁判断,所以也就没有必要用GCD