iOS之單例模式初探

單例模式多是設計模式中最簡單的形式了,這一模式的意圖就是使得類中的一個對象成爲系統中的惟一實例。它提供了對類的對象所提供的資源的全局訪問點。所以須要用一種只容許生成對象類的惟一實例的機制。下面讓咱們來看下單例的做用:

  • 能夠保證的程序運行過程,一個類只有一個示例,並且該實例易於供外界訪問設計模式

  • 從而方便地控制了實例個數,並節約系統資源。安全

單例模式的使用場合

  • 類只能有一個實例,而且必須從一個爲人數值的訪問點對其訪問。框架

  • 這個惟一的實例只能經過子類化進行拓展,而且拓展的對象不會破壞客戶端代碼。學習

在Objective-C中方法都是公有的,並且OC的語言自己是動態類型的,所以全部類均可以相互發送對方的消息。,而且Cocoa框架使用計數的內存管理方式來維護對象的內存中的生存期。
下面讓咱們看一下OC當中的單例模式的寫法,首先單例模式在ARC\MRC環境下的寫法有所不一樣,須要編寫2套不一樣的代碼
  • 能夠用宏判斷是否爲ARC環境spa

    #if _has_feature(objc_arc)#else//MRC#endif

    單例模式- ARC -方法一

  • ARC中單例模式的實現.net

  • 在 .m中保留一個全局的static的實例線程

 static id _instance; //重寫allocWithZone:方法,在這裏建立惟一的實例(注意線程安全)
 + (instancetype)allocWithZone:(struct _NSZone *)zone
{    @synchronized(self) {        if (_instance == nil) {
            _instance = [super allocWithZone:zone];
        }
    }    return _instance;
}
  • 提供1個類方法讓外界訪問惟一的實例設計

    + (instancetype)sharedInstanceTool{    @synchronized(self){        if(_instance == nil){
            _instance = [[self alloc] init];
        }
    }    return _instance;
}
  • 實現copyWithZone:方法指針

      -(id)copyWithZone:(struct _NSZone *)zone{  return _instance;
      }
    咱們在sharedInstanceTool,首先檢查類的惟一實例是否已經建立,若是就會建立實例並將其返回。而之因此調用super而不是self,是由於已經在self中重載了基本的對象分配的方法,須要借用父類的功能來幫助處理底層內存的分配。
    allocWithZone:(struct _NSZone*)zone方法中,只是返回從sharedInstanceTool方法返回的類實例。而一樣的在Cocoa框架中調用allocWithZone:(struct _NSZone*)zone會分配內存,引用計數會設置爲1,而後返回實例。一樣的重寫(id)copyWithZone:(struct _NSZone *)zone方法,也是爲了保證不會返回實例的副本,而是返回self.返回同一個實例。

方法二:

+(instancetype)sharedInstance {    static WMSingleton *singleton = nil;    if (! singleton) {
        singleton = [[self alloc] initPrivate];
    }    return singleton;
}

- (instancetype)init {    @throw [NSException exceptionWithName:@"這個是個單例"
                                   reason:@"應該這樣調用 [WMSingleton sharedInstance]"
                                 userInfo:nil];    return nil;
}//實現本身真正的私有初始化方法- (instancetype)initPrivate {    self  = [super init];    return self;
}

上面這段代碼中將singleton指針聲明爲靜態變量。當某個定義了靜態變量的方法返回時,程序不會釋放相應的變量。####singleton變量的初始值是nil,當程序第一次執行sharedInstance方法時會建立一個對象,並將新建立的對象的地址賦值給singleton變量。當徐成再次執行sharedInstance方法時,不管多少次singleton變量仍然會指向最初那個建立的對象。由於指向對象的singleton變量是強引用的,而且程序永遠不會釋放該變量,因此singleton變量指向的對象也不會釋放。

線程安全。

上面的實例中咱們經過@synchronized 來添加了一個互斥鎖,以此來保證線程安全。而如今咱們開始嘗試用線程的方式來實現一個加單的單例。

static WMObject *_instance;

+ (instancetype)allocWithZone:(struct _NSZone *)zone
{    static dispatch_once_t onceToken;    dispatch_once(&onceToken, ^{
        _instance = [super allocWithZone:zone];
    });    return _instance;
}

+ (instancetype)sharedInstance
{    static dispatch_once_t onceToken;    dispatch_once(&onceToken, ^{
        _instance = [[self alloc] init];
    });    return _instance;
}

- (id)copyWithZone:(NSZone *)zone
{    return _instance;
}
從上面的代碼咱們能夠看到,實現的思路基本上也是一致的咱們在sharedInstanceTool,首先檢查類的惟一實例是否已經建立,若是就會建立實例並將其返回。而略有不一樣的地方就是咱們此次經過dispatch_once_t來保證線程的安全性。至於dispatch_once_t的用法這裏就一一贅述了,線程的相關教程都會有其相關的描述。

到了這裏一個簡單的單例模式基本實現完成了,那麼咱們能夠嘗試着把它封裝到一個宏裏,而後方便其之後的調用

建立一個WMSingleton.h

// .h文件#define WMSingletonH(name) + (instancetype)shared##name;

// .m文件#define WMSingletonM(name) 
static id _instance; 
+ (instancetype)allocWithZone:(struct _NSZone *)zone
 { 
     static dispatch_once_t onceToken; 
     dispatch_once(&onceToken, ^{
          _instance = [super allocWithZone:zone];
       });
     return _instance; 
 } 
 
 + (instancetype)shared##name 
 { 
    static dispatch_once_t onceToken; 
     dispatch_once(&onceToken, ^{ 
         _instance = [[self alloc] init];
      }); 
      return _instance;
 } 
   
 - (id)copyWithZone:(NSZone *)zone 
 {
     return _instance; 
 }
使用方法
//.h類//引入這個宏文件#import "WMSingleton.h"@interface WMObject : NSObjectWMSingletonH(object)@end//.m類@implementation WMObjectWMSingletonM(Car)@end

經過上面的演練咱們基本上學習了一些基本的單例模式而後在Cocoa Touch框架中一樣存在着大量的單例模式讓咱們來學習,好比UIApplicationUIAccelerometer、以及NSFileManager等等。因此在單例模式的學習上仍是依舊的任重道遠呀。。。

相關文章
相關標籤/搜索