轉載請出名出處: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 就是單例類。
單例模式確保某一個類只有一個實例,並且自行實例化並向整個系統提供這個實例