单例模式用于当一个类只能有一个实例的时候, 通常情况下这个“单例”代表的是某一个物理设备比如打印机,或是某种不可以有多个实例同时存在的虚拟资源或是系统属性比如一个程序的某个引擎或是数据。用单例模式加以控制是非常有必要的。
单例模式需要达到的目的
1. 封装一个共享的资源
2. 提供一个固定的实例创建方法
3. 提供一个标准的实例访问接口
单例类保证了应用程序的生命周期中有且仅有一个该类的实例对象,而且易于外界访问。
- @implementation AppShareDataManager
- static AppShareDataManager * shareDataManager = nil;
- @synthesize theCurrentLanguage;
- @synthesize presentModalFlag;
- ..........
- +(AppShareDataManager *) sharedManager
- {
- if( shareDataManager == nil )
- {
- shareDataManager = [ [ AppShareDataManager alloc ] init ];
- }
- return shareDataManager;
- }
- -(id)init{
- self = [super init];
- if(self){
- //对象实例初始化
- theCurrentLanguage = [ZONUserDefaultManager getAppDefaultLanguage];
- ........
- }
- return self;
- }
调试发现
AppShareDataManager *A = [[AppShareDataManager alloc] init];
NSLog(@"A:%@",A);
AppShareDataManager *B = [AppShareDataManager sharedManager];
NSLog(@"B:%@",B);
打印出的是
2013-02-28 23:27:25.368 ZON2012[10647:c07] A:<AppShareDataManager: 0x12638630>
2013-02-28 23:27:25.369 ZON2012[10647:c07] B:<AppShareDataManager: 0xb584b40>
不是一个内存地址,也就是不是同一个实体!
这是apple官方的一个单例建议:
- /* Singleton.h */
- #import <Foundation/Foundation.h>
- @interface Singleton : NSObject
- + (Singleton *)instance;
- @end
- /* Singleton.m */
- #import "Singleton.h"
- static Singleton *instance = nil;
- @implementation Singleton
- + (Singleton *)instance {
- if (!instance) {
- instance = [[super allocWithZone:NULL] init];
- }
- return instance;
- }
- + (id)allocWithZone:(NSZone *)zone {
- return [self instance];
- }
- - (id)copyWithZone:(NSZone *)zone {
- return self;
- }
- - (id)init {
- if (instance) {
- return instance;
- }
- self = [super init];
- return self;
- }
- - (id)retain {
- return self;
- }
- - (oneway void)release {
- // Do nothing
- }
- - (id)autorelease {
- return self;
- }
- - (NSUInteger)retainCount {
- return NSUIntegerMax;
- }
- @end
这是一种很标准的Singleton实现,中规中矩。不过这种实现并不是线程安全的。所以各路大神都各显神威,给出了多种单例模式的实现。
现在把他加强下:
- static MyClass *class = nil;
- @implementation MyClass
- +(MyClass *)sharedMyClass{
- @synchronized(self){ //为了确保多线程情况下,仍然确保实体的唯一性
- if (!class) {
- [[self alloc] init]; //该方法会调用 allocWithZone
- }
- }
- return class;
- }
- +(id)allocWithZone:(NSZone *)zone{
- @synchronized(self){// //为了确保多线程情况下,仍然确保实体的唯一性
- if (!class) {
- class = [super allocWithZone:zone]; //确保使用同一块内存地址
- return class;
- }
- }
- return nil;
- }
- -(id)init
- {
- if(class){
- return class;
- }
- if(self = [super init]){
- //进行一些初始化
- }
- return self ;
- }
- - (id)copyWithZone:(NSZone *)zone;{
- return self; //确保copy对象也是唯一
- }
- -(id)retain{
- return self; //确保计数唯一
- }
- - (unsigned)retainCount
- {
- return UINT_MAX; //装逼用的,这样打印出来的计数永远为-1
- }
- - (id)autorelease
- {
- return self;//确保计数唯一
- }
- - (oneway void)release
- {
- //重写计数释放方法 do nothing
- }
- @end
再调试
MyClass *A = [[MyClass alloc] init];
NSLog(@"A:%@",A);
MyClass *B = [MyClass sharedMyClass];
NSLog(@"B:%@",B);
MyClass *C = [A copy];
NSLog(@"C:%@",C);
打印出的是
A:<MyClass: 0x6a1e130>
B:<MyClass: 0x6a1e130>
C:<MyClass: 0x6a1e130>
都是指向同一块内存地址
-----------------------------------切糕分割线--------------------------------------------------------
然而这个人(http://eschatologist.net/blog/?p=178)觉的繁琐,所以给出如下实现:
- @interface SomeManager : NSObject
- + (id)sharedManager;
- @end
- /* 非线程安全的实现 */
- @implementation SomeManager
- + (id)sharedManager {
- static id sharedManager = nil;
- if (sharedManager == nil) {
- sharedManager = [[self alloc] init];
- }
- return sharedManager;
- }
- @end
- /* 线程安全的实现 */
- @implementation SomeManager
- static id sharedManager = nil;
- + (void)initialize {
- if (self == [SomeManager class]) {
- sharedManager = [[self alloc] init];
- }
- }
- + (id)sharedManager {
- return sharedManager;
- }
- @end
-----------------------------------切糕分割线--------------------------------------------------------
自苹果引入了Grand Central Dispatch (GCD)(Mac OS 10.6和iOS4.0)后,利用GCD(Grand Central Dispatch)和ARC(Automatic Reference Counting)实现单例。
- +(SchoolManager *)sharedInstance
- {
- __strong static SchoolManager *sharedManager;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- sharedManager = [[SchoolManager alloc] init];
- });
- return sharedManager;
- }
函数void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);其中第一个参数predicate,该参数是检查后面第二个参数所代表的代码块是否被调用的谓词,第二个参数则是在整个应用程序中只会被调用一次的代码块。dispach_once函数中的代码块只会被执行一次,而且还是线程安全的。
看到如下一篇文章,用宏实现(https://gist.github.com/lukeredpath/1057420):
ExampleClass.m
GCDSingleton.h