单例:在写项目的时候,我们实际用到了很多系统给我们提供的单例类;
如:
[UIApplication sharedApplication]; //应用程序实例类 [NSNotificationCenter defaultCenter];//消息中心实例类 [NSFileManager defaultManager];//文件管理实例类 [NSUserDefaults standardUserDefaults];//应用程序设置 [NSURLCache sharedURLCache];//请求缓存实例类
下面我们学习下单例:
一 、 单例的定义和生命周期
-
单例类,在整个项目中只有一个实例,并提供一个类方法供全局调用,在编译时初始化这个类,然后一直保存在内存中,到程序退出时由系统自动释放这部分内存。
-
一般在程序中,经常调用的类,如工具类、公共跳转类等都会采用单例模式;
-
在程序中,一个单例类在程序中只能初始化一次,为了保证在使用中始终都是存在的,所以单例是在存储器的全局区域,在编译时分配内存,只要程序还在运行就会一直占用内存,在APP结束后由系统释放这部分内存内存。
二、单例的实现
-
(1) 为单例对象创建一个静态实例,可以写成全局的,也可以在类方法里面实现,并初始化为nil;
(2) 实现一个实例构造方法,检查上面声明的静态实例是否为nil,如果是,则创建并返回一个本类的实例;
(3) 重写allocWithZone方法,用来保证其他人直接使用alloc和init试图获得一个新实力的时候不产生一个新实例;
(4) 适当实现copyWithZone,mutableCopyWithZone,非arc下还需要实现release和autorelease方法。
代码实现 ------------1
-
首先定义一个LvSingleClass单例类
-
在 LvSingleClass.h文件中实现如下
@interface LvSingleClass : NSObject + (LvSingleClass *)sharedSingleClass; @end
-
在LvSingleClass.m添加如下
static LvSingleClass * singleClass = nil; + (LvSingleClass *)sharedSingleClass { //可以用synchronized // @synchronized(self){ // if (singleClass == nil) { // singleClass = [[LvSingleClass alloc] init]; // } // } //可以用dispatch_once static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ singleClass = [[LvSingleClass alloc] init]; }); return singleClass; } - (id)init { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ singleClass = [super init]; }); return singleClass; } + (id)allocWithZone:(struct _NSZone *)zone { if (singleClass == nil) { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ singleClass = [super allocWithZone:zone]; }); } return singleClass; } + (id)copyWithZone:(struct _NSZone *)zone { return singleClass; } + (id)mutableCopyWithZone:(struct _NSZone *)zone { return singleClass; }
//创建单例的时候可以用synchronized和dispatch_once 个人觉得用后者
这样一个比较完整的单例实现,这样在我们init,alloc,copy,mutableCopy时,都能保证只创建唯一单例。
例如 我们 NSLog(@"---%@----%@",[[LvSingleClass alloc] init], [LvSingleClass sharedSingleClass]);
调用打印
会发现 如下 地址是一样的
2018-10-31 11:01:39.779933+0800 Single[19695:5948562]
—<LvSingleClass: 0x60000000c150>----<LvSingleClass: 0x60000000c150>
还有另一种方法 ---------2
-
首先定义一个LvOtherSingleClass单例类
-
在 LvOtherSingleClass.h文件中实现如下
+ (LvOtherSingleClass *)sharedSingle; +(instancetype) new __attribute__((unavailable("单例类只能初始化一次"))); -(instancetype) copy __attribute__((unavailable("单例类只能初始化一次"))); -(instancetype) mutableCopy __attribute__((unavailable("单例类只能初始化一次")));
-
在 LvOtherSingleClass.m文件中实现如下
static LvOtherSingleClass * singleClass = nil; + (LvOtherSingleClass *)sharedSingle { //可以用synchronized和dispatch_once 个人觉得用后者 //可以用synchronized // @synchronized(self){ // if (singleClass == nil) { // singleClass = [[LvOtherSingleClass alloc] init]; // } // } //可以用dispatch_once static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ singleClass = [[LvOtherSingleClass alloc] init]; }); return singleClass; } +(void)initialize { [LvOtherSingleClass sharedSingle]; } + (instancetype)alloc { //如果已经初始化了 if(singleClass) { return singleClass; } return [super alloc]; }
这样一个比较完整的单例也实现,这样在我们new,copy,mutableCopy时,会找不到哪些方法。
三 、优缺点
优点
1、整个项目中只会实例化一次;
2、在整个项目中只实例化一个对象,节省系统内存,提高程序的运行效率
缺点
1、不能被重写、不能被继承、不能被扩展
2、创建单例对象之后,只要程序一直运行就一直占用这系统的内存,在不用该对象的时候也不能销毁消耗着系统的内存