在程序运行中,一个类只有一个实例,就叫单例。当我们想要在整个应用程序中,指定一份资源只能被初始化一次,并且实现共享的时候我们就可以使用单例模式,也就是创建一个单例类,用它来管理指定资源。
####一、如何在创建一份ARCMRC通用的单例?
- 在类的内部提供一个static修饰的全局变量
- 提供一个类方法,方便外界访问
- 重写+allocWithZone方法,保证永远都只为单例对象分配一次内存空间
- 严谨起见,重写-copyWithZone方法和-MutableCopyWithZone方法
如果是MRC则还需要以下步骤: 5. 重写release方法 6. 重写retain方法 7. 建议在retainCount方法中返回一个最大值
我们来看一下代码:
//
// STSingleton.m
// 单例模式
//
// Created by Swift Gao on 16/6/24.
// Copyright © 2016年 Swift Gao. All rights reserved.
//
#import "STSingleton.h"
@implementation STSingleton
static STSingleton *_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)shareSTSingleton{
return [[self alloc]init];
}
- (id)copyWithZone:(NSZone *)zone{
return _instance;
}
-(id)mutableCopyWithZone:(NSZone *)zone{
return _instance;
}
#if __has_feature(objc_arc)
//ARC
//什么都不做
#else
//MRC
//如果用户release了一次,那么什么都不做,因为单例模式在整个程序运行过程中都拥有且
//只有一份,程序退出之后被释放,所以不需要对引用计数器操作
-(oneway void)release
{
}
//在MRC环境下,如果用户retain了一次,那么直接返回instance变量,不对引用计数器+1
-(instancetype)retain
{
return _instance;
}
//惯用法,有经验的程序员通过打印retainCount这个值可以猜到这是一个单例
-(NSUInteger)retainCount
{
return MAXFLOAT;
}
#endif
@end
复制代码
####二、单例类能使用继承吗? 答案是不行的,为什么?
单例类中使用了static修饰的全局变量,继承的时候也会将其继承过来,而这个变量只能创建一次。如果你真的去尝试继承,你会发现,你用父类和子类创建的对象是同一个,继承失去了意义,这并不是我们想要的。
我们使用继承的目的是减少代码量,提高代码的复用以提高开发效率并使得项目结构更加整洁。如果我们也想要使得单例类可以复用,而我们已经知道无法通过继承的方式去实现,那么有没有其他方法?
当然是有的,我们这边使用带参数的宏定义来解决问题。当然,如果有幸让身为大神的你看到这篇文章并且你刚好也有其他更好的解决方案,烦请告知,不胜感激。
创建一个宏定义头文件,直接看代码吧:
//
// Singleton.h
// 单例模式
//
// Created by Swift Gao on 16/6/25.
// Copyright © 2016年 Swift Gao. All rights reserved.
//
#define singleH(name) +(instancetype)share##name;
//反斜杠用于拼接跨行
//if
#if __has_feature(objc_arc)
//ARC
//define
#define singleM(name) static id _instance;\
+(instancetype)allocWithZone:(struct _NSZone *)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
#else
//define
#define singleM(name) static id _instance;\
+(instancetype)allocWithZone:(struct _NSZone *)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
#endif
复制代码
如何使用? 如果你要创建一个单例类:Bluetooth
//
// Bluetooth.h
// 单例模式
//
// Created by Swift Gao on 16/6/24.
// Copyright © 2016年 Swift Gao. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "Singleton.h"
@interface Bluetooth : NSObject
//这里使用了宏定义
singleH(Bluetooth)
@end
复制代码
//
// Bluetooth.m
// 单例模式
//
// Created by Swift Gao on 16/6/24.
// Copyright © 2016年 Swift Gao. All rights reserved.
//
#import "Bluetooth.h"
@implementation Bluetooth
singleM(Bluetooth)
@end
复制代码
是的,就这么简单,一次编写,可以到处使用了。