转载请出名出处:http://my.oschina.net/liuchuanfeng/blog/660917
设计模式
如下为翻译部分:安全
翻译自:http://www.galloway.me.uk/tutorials/singleton-classes/ 如有不精确之处,还望不吝赐教。函数
单例模式singleton pattern是常常使用的设计模式,它不用传递参数,就能在两个不一样的代码块之间实现数据共享测试
好比:从任何地方调用UIApplication 的 sharedApplication方法,都会返回与当前运行程序相关的UIApplication实例。atom
如何实现单例类:(ARC)spa
#import <foundation/Foundation.h> @interface MyManager : NSObject { NSString *someProperty; } @property (nonatomic, retain) NSString *someProperty; + (id)sharedManager; @end
#import "MyManager.h" @implementation MyManager @synthesize someProperty; #pragma mark Singleton Methods + (id)sharedManager { static MyManager *sharedMyManager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedMyManager = [[self alloc] init]; }); return sharedMyManager; } - (id)init { if (self = [super init]) { someProperty = [[NSString alloc] initWithString:@"Default Property Value"]; } return self; } - (void)dealloc { // Should never be called, but just here for clarity really. } @end
上面定义了静态变量sharedMyManager 在sharedManager里只被实例化一次,GCD的dispatch_once方法保证只被建立一次,而且是线程安全的。.net
固然,若是不想使用GCD,可使用下面的代码:线程
+ (id)sharedManager { static MyManager *sharedMyManager = nil; @synchronized(self) { if (sharedMyManager == nil) sharedMyManager = [[self alloc] init]; } return sharedMyManager; }
用下面的方法能够从任何一个地方调用这个单例
翻译
MyManager *sharedManager = [MyManager sharedManager];
单例使用普遍,好比处理CoreLocation or CoreData函数设计
非ARC代码:
#import "MyManager.h" static MyManager *sharedMyManager = nil; @implementation MyManager @synthesize someProperty; #pragma mark Singleton Methods + (id)sharedManager { @synchronized(self) { if(sharedMyManager == nil) sharedMyManager = [[super allocWithZone:NULL] init]; } return sharedMyManager; } + (id)allocWithZone:(NSZone *)zone { return [[self sharedManager] retain]; } - (id)copyWithZone:(NSZone *)zone { return self; } - (id)retain { return self; } - (unsigned)retainCount { return UINT_MAX; //denotes an object that cannot be released } - (oneway void)release { // never release } - (id)autorelease { return self; } - (id)init { if (self = [super init]) { someProperty = [[NSString alloc] initWithString:@"Default Property Value"]; } return self; } - (void)dealloc { // Should never be called, but just here for clarity really. [someProperty release]; [super dealloc]; } @end
如下加入个人理解:
不知你是否在上面ARC下用以下代码测试过
MyManager *mm1 = [[MyManager alloc] init]; MyManager *mm2 = [[MyManager alloc] init]; MyManager *mm3 = [[MyManager alloc] init]; NSLog(@"\n%@\n%@\n%@",mm1,mm2,mm3); MyManager *mm4 = [MyManager sharedManager]; MyManager *mm5 = [MyManager sharedManager]; NSLog(@"\n%@\n%@",mm4,mm5);
mm1 mm2 mm3的值(地址)是不同的,mm4 mm5同样,重写allocWithZone就能保证mm1 mm2 mm3的值同样了。固然若是须要copy,则要重写copyWithZone
+(id)allocWithZone:(NSZone *)zone{ @synchronized(self){ if (sharedMyManager == nil) { sharedMyManager = [super allocWithZone:zone]; //确保使用同一块内存地址 return sharedMyManager; } return sharedMyManager; } } - (id)copyWithZone:(NSZone *)zone { return self; }
为何实现allocWithZone、copyWithZone这两个方法?
建立对象的时候,alloc表示申请内存,init表示初始化,程序在alloc时,会在allocWithZone这个方法申请内存,咱们只要在这个方法中调用sharedManager返回单例便可。这样就不会申请屡次内存了。拷贝对象以此类推,同理所得,要重写copyWithZone。这样就保证了这个类只被实例化了一次。
@synchronized 保证线程安全
单例能够用来传值,系统UIApplication NSUserDefaults 就是单例类。
单例模式确保某一个类只有一个实例,并且自行实例化并向整个系统提供这个实例