ios-設計模式-單例

轉載請出名出處: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 就是單例類。

單例模式確保某一個類只有一個實例,並且自行實例化並向整個系統提供這個實例

相關文章
相關標籤/搜索