由于iOS开发中经常会用到单例,所以就做个简单的总结。
单例模式
- 作用:
可以保证在程序运行过程中,一个类只有一个实例,而且该实例易于供外界访问,从而方便的控制了实例个数,并节约系统资源 - 使用场合:
在整个应用程序中,共享一份资源(这份资源只需要创建初始化一次)
arc环境下实现单例模式
#import <Foundation/Foundation.h>
//重写copy的相关方法时必须引入copy的相关文件
@interface danli : NSObject<NSCopying,NSMutableCopying>
//类方法
//1.方便访问
//2.标明身份
//3.命名规范 share/default + 类名
+(instancetype)shareDanli;
@end
#import "danli.h"
@implementation danli
//0.提供全局变量
static danli *_instance;
//1.alloc
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
//method 1
//加互斥锁解决多线程访问安全问题
@synchronized(self){
if (_instance==nil) {
_instance=[super allocWithZone:zone];
}
}
//method 2
//本身就是线程安全的,不需要担心多线程安全问题
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance=[super allocWithZone:zone];
});
return _instance;
}
//2.提供类方法
+(instancetype)shareDanli{
return [[self alloc]init];
}
//3.严谨,因为有的时候不止是alloc或new方法创建
-(id)copyWithZone:(NSZone *)zone{
return _instance;
}
-(id)mutableCopyWithZone:(NSZone *)zone{
return _instance;
}
@end
以上就是在arc的环境下构建单例的方法,mrc的环境下构建单例的方法差不多,就是多重写几个方法
mrc环境下实现单例模式
首先,设置一下mrc的开发环境,如下图所示
其次,因为在mrc环境下需要在创建实例后进行release操作,但这显然和单例的目标相违背,所以为了不进行销毁,我们可以重写以下方法,
-(oneway void)release{
}
-(instancetype)retain{
return _instance;
}
-(NSUInteger)retainCount{
return MAXFLOAT;
}
这样就已经实现了我们的目标
但是考虑到如果经常切换mrc和arc的环境,我们就需要经常修改相关方法,所以为了解决这个问题,我们可以使用条件编译来动态的根据开发环境来进行mrc和arc的不同考虑,也就是将mrc的相关代码放在条件编译的else语句中,这样也就不需要经常修改代码了
//条件编译
#if __has_feature(objc_arc)
//arc
#else
//mrc
-(oneway void)release{
}
-(instancetype)retain{
return _instance;
}
-(NSUInteger)retainCount{
return MAXFLOAT;
}
#endif
以上已经完成了单例的操作,但是在一个大的项目中,我们肯定不会只有一个单例,而单例的代码其实也都差不多,如果每次都进行复制,在代码的复用问题上又做的不是很好,所以我们可以考虑将单例的代码写成宏,这样就可以方便使用了,其中,这里使用了带参数的宏,参数即为name,也就是我们自己设置的单例名称
- 定义.h文件的宏
#define singerH(name) +(instancetype)share##name;
- 定义.m文件的宏,其中也是使用条件编译区分arc和mrc的开发环境
#if __has_feature(objc_arc)
//arc
#define singerM(name) static id *_instance;\
+(instancetype)allocWithZone:(struct _NSZone *)zone\
{\
@synchronized(self){\
if (_instance==nil) {\
_instance=[super allocWithZone:zone];\
}\
}\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instance=[super allocWithZone:zone];\
});\
return _instance;\
}\
+(instancetype)share##name{\
return [[self alloc]init];\
}\
-(id)copyWithZone:(NSZone *)zone{\
return _instance;\
}\
-(id)mutableCopyWithZone:(NSZone *)zone{\
return _instance;\
}
#else
//mrc
#define singerM(name) static id *_instance;\
+(instancetype)allocWithZone:(struct _NSZone *)zone\
{\
@synchronized(self){\
if (_instance==nil) {\
_instance=[super allocWithZone:zone];\
}\
}\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instance=[super allocWithZone:zone];\
});\
return _instance;\
}\
+(instancetype)share##name{\
return [[self alloc]init];\
}\
-(id)copyWithZone:(NSZone *)zone{\
return _instance;\
}\
-(id)mutableCopyWithZone:(NSZone *)zone{\
return _instance;\
}\
-(oneway void)release{\
}\
-(instancetype)retain{\
return _instance;\
}\
-(NSUInteger)retainCount{\
return MAXFLOAT;\
}\
#endif
在使用时,只要在自己创建的单例文件中调用相关的参数宏就可以了
以上,就是iOS开发中单例的相关使用方法