引用:http://blog.csdn.net/lovefqing/article/details/8516536#t3
http://blog.csdn.net/kindazrael/article/details/7917863
单例模式用于当一个类只能有一个实例的时候, 通常情况下这个“单例”代表的是某一个物理设备比如打印机,或是某种不可以有多个实例同时存在的虚拟资源或是系统属性比如一个程序的某个引擎或是数据。最简单的一个例子是,当用户打开QQ空间播放音乐的时候,这里就是一个单例,如果不是单例的话,点击其他页面QQ音乐就会自动从头开始播放。用单例模式加以控制是非常有必要的。
单例模式需要达到的目的
1. 封装一个共享的资源
2. 提供一个固定的实例创建方法
3. 提供一个标准的实例访问接口
单例模式的创建
本文以创建一个MySingletonClass的单例模式为例。首先,我们需要定义一个类MySingletonClass.
[cpp] view plaincopy
- @interface MySingletonClass:NSObject {
- }
并且为其添加一个类方法(注意,这里不是实例方法)+(id)sharedInstance;一个基本的实现写法如下:
static MySingletonClass *sharedInstance = nil;
- +(MySingletonClass *)sharedInstance{
- @synchronized(self) {
- if(sharedInstance == nil) {
- sharedInstance = [[MySingletonClass alloc]init];
- }
- }
- return sharedInstance;
- }
在上面的代码中(用到了关键字@synchronized是为了保证我们的单例的线程级别的安全,可以适用于多线程模式下。)static变量sharedCLDelegate用于存储一个单例的指针,并且强制所有对该变量的访问都必须通过类方法 +(id)sharedInstance,在对 +(id)sharedInstance第一次调用时候完成实例的创建。这里值得留意一下的是,上面代码中用的是[[selfclass] alloc],而不是 [MySingletonClass alloc],一般情况下这两种写法产生同样的效果.
对实例化的控制
为了完全的实现实例的单态性,必须通过一定手段来避免实例多次被创建。+(id)sharedInstance控制了单例的创建和访问,但是并不能控制其它地方的代码通过alloc方法来创建更多的实例,因此我们还要重载任何一个涉及到allocation的方法,这些方法包括 +new, +alloc,+allocWithZone:, -copyWithZone:, 以及 -mutableCopyWithZone:另外,+(id)sharedInstance也需要稍作修改。
- + (id)hiddenAlloc
- {
- return [super alloc];
- }
- + (id)alloc
- {
- NSLog(@"%@: use +sharedInstance instead of +alloc", [[self class] name]);
- return nil;
- }
- + (id)new
- {
- return [self alloc];
- }
- +(id)allocWithZone:(NSZone*)zone
- {
- return [self alloc];
- }
- - (id)copyWithZone:(NSZone *)zone
- { // -copy inherited from NSObject calls -copyWithZone:
- NSLog(@"MySingletonClass: attempt to -copy may be a bug.");
- [self retain];
- return self;
- }
- - (id)mutableCopyWithZone:(NSZone *)zone
- {
- // -mutableCopy inherited from NSObject calls -mutableCopyWithZone:
- return [self copyWithZone:zone];
- }
- +(id)sharedInstance修改如下:
- + (MySingletonClass *)sharedInstance {
- @synchronized(self) {
- if (sharedCLDelegate == nil) {
- [[[self class] hiddenAlloc] init]; // assignment not done here
- }
- }
- return sharedCLDelegate;
- }
如果不考虑类的子类化,+hiddenAlloc这个方法可以省略。由于我们是用[selfclass]来实现类型的动态识别,用[[selfclass] hiddenAlloc]可以避免调用到被重载过的alloc方法。此外,hiddenAlloc也为可能的子类化提供了一个调用原始alloc方法的机会。上面重载过的alloc方法只是给出一个log信息并且返回nil。Copying方法里只是简单的增加了retain的计数并没有返回一个新的实例。这也正体现了单例模式的性质,因为技术上来讲,拷贝一个单例是错误的(因为是“单例”)所以在copyWithZone方法中我们给出了一个错误信息,当然也可以扔出一个exception。
单例的销毁
通常我们在 -(void)applicationWillTerminate:(UIApplication *)application方法中调用如下方法:
- + (void)attemptDealloc
- {
- if ([sharedCLDelegate retainCount] != 1)
- return;
- [sharedCLDelegate release];
- myInstance = nil;
- }
值得注意的是,上面这个attemptDealloc方法顾名思义,只是试图释放掉这个单例。如果retain的计数不为1,说明还有其他地方对该单例发送过retain消息。考虑到一个单例模式的生存周期是整个程序结束为止。所以,在程序的任何一个地方都没有必要向这个单例发送retain消息,即便是对这个单例有引用。而是调用sharedInstance方法来引用这个单例,这样做是安全的,也是合乎单例模式的技术含义的。
这里需要设置一个参数,手动管理内存。
iOS中的单例模式应用
iOS中好几个类都是采用了单例模式,比如NSApplication, NSFontManager, NSDocumentController,NSHelpManager, NSNull,NSProcessInfo, NSScriptExecutionContext, NSUserDefaults.
- 官方建议
- 由于自己设计单态模式存在一定风险,主要是考虑到可能在多线程情况下会出现的问题,因此苹果官方建议使用以下方式来实现单态模式:
- static MyGizmoClass *sharedGizmoManager = nil;
- + (MyGizmoClass*)sharedManager
- {
- @synchronized(self) {
- if (sharedGizmoManager == nil) {
- [[self alloc] init]; // assignment not done here
- }
- }
- return sharedGizmoManager;
- }
- + (id)allocWithZone:(NSZone *)zone
- {
- @synchronized(self) {
- if (sharedGizmoManager == nil) {
- sharedGizmoManager = [super allocWithZone:zone];
- return sharedGizmoManager; // assignment and return on first allocation
- }
- }
- return nil; //on subsequent allocation attempts return nil
- }
- - (id)copyWithZone:(NSZone *)zone
- {
- return self;
- }
- - (id)retain
- {
- return self;
- }
- - (unsigned)retainCount
- {
- return UINT_MAX; //denotes an object that cannot be released
- }
- - (void)release
- {
- //do nothing
- }
- - (id)autorelease
- {
- return self;
- }
- 由于单例模式基本要符合上面的设计,当有很多类都要设计成单例模式时,可以定义
- 一个单例模板的宏,以提高程序的重用和减少不必要错误。
- #define SYNTHESIZE_SINGLETON_FOR_CLASS(classname) \
- \
- static classname *shared##classname = nil; \
- \
- + (classname *)shared##classname \
- { \
- @synchronized(self) \
- { \
- if (shared##classname == nil) \
- { \
- shared##classname = [[self alloc] init]; \
- } \
- } \
- \
- return shared##classname; \
- } \
- \
- + (id)allocWithZone:(NSZone *)zone \
- { \
- @synchronized(self) \
- { \
- if (shared##classname == nil) \
- { \
- shared##classname = [super allocWithZone:zone]; \
- return shared##classname; \
- } \
- } \
- \
- returnnil; \
- } \
- \
- - (id)copyWithZone:(NSZone *)zone \
- { \
- returnself; \
- } \
- \
- - (id)retain \
- { \
- returnself; \
- } \
- \
- - (NSUInteger)retainCount \
- { \
- return NSUIntegerMax; \
- } \
- \
- - (void)release \
- { \
- } \
- \
- - (id)autorelease \
- { \
- returnself; \
- }
用法:假设AppPreference类要实现单例
#import "AppPreference.h"
#import "SingletonTemplate.h"
@implementation AppPreference
//使用宏模版生成单例所需要的code
SYNTHESIZE_SINGLETON_FOR_CLASS(AppPreference)
//这是一个测试方法
+ (void)test {
//使用单例
AppPreference *appPreference = [AppPreference sharedAppPreference];
}
@end