iOS 的單例模式 dispatch_once

iOS 的單例模式 dispatch_once


      有些變量只需要初始化一次(如從文件中讀取配置參數,讀取設備型號等等),可以使用dispatch_once來進行讀取優化,保證只調用API一次,以後就只要直接訪問變量即可.

WeatherClient.h

#import "AFHTTPClient.h"

@interface WeatherClient : AFHTTPClient

+(WeatherClient *)sharedClient;

@end

WeatherClient.m

#import "WeatherClient.h"

@implementation WeatherClient

+(WeatherClient *)sharedClient
{
    static WeatherClient *sharedClient=nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken,^{sharedClient =[[WeatherClient alloc] initWithBaseURL:[NSURL URLWithString:API]];
    });
    return sharedClient;
}


@end

在軟件工程中,單例是一種用於實現單例的數學概念,即將類的實例化限制成僅一個對象的設計模式。
或者我的理解是:
單例是一種類,該類只能實例化一個對象。
    儘管這是單例的實際定義,但在Foundation框架中不一定是這樣。比如NSFileMangerNSNotificationCenter,分別通過它們的類方法defaultManagerdefaultCenter獲取。儘管不是嚴格意義的單例,這些類方法返回一個可以在應用的所有代碼中訪問到的類的共享實例。在本文中我們也會採用該方法。
    使用Objective-C實現單例模式的最佳方式向來有很多爭論,開發者(包括Apple在內)似乎每幾年就會改變他們的想法。當Apple引入了Grand Central Dispatch (GCD)(Mac OS 10.6和iOS4.0),他們也引入了一個很適合用於實現單例模式的函數。
    該函數就是dispatch_once
void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);
    該函數接收一個dispatch_once用於檢查該代碼塊是否已經被調度的謂詞(是一個長整型,實際上作爲BOOL使用)。它還接收一個希望在應用的生命週期內僅被調度一次的代碼塊,對於本例就用於shared實例的實例化。
dispatch_once不僅意味着代碼僅會被運行一次,而且還是線程安全的,這就意味着你不需要使用諸如@synchronized之類的來防止使用多個線程或者隊列時不同步的問題。
    Apple的GCD Documentation證實了這一點:
如果被多個線程調用,該函數會同步等等直至代碼塊完成。
    實際要如何使用這些呢?
    好吧,假設有一個AccountManager類,你想在整個應用中訪問該類的共享實例。你可以按如下代碼簡單實現一個類方法:
+ (AccountManager *)sharedManager { 
    static AccountManager *sharedAccountManagerInstance = nil; 
 static dispatch_once_t predicate;
 dispatch_once(&predicate, ^{       
          sharedAccountManagerInstance = [[self alloc] init]; 
     });
    return sharedAccountManagerInstance; 
}
    這就意味着你任何時候訪問共享實例,需要做的僅是:
AccountManager *accountManager = [AccountManager sharedManager];
    就這些,你現在在應用中就有一個共享的實例,該實例只會被創建一次。
    該方法有很多優勢: 
           1 線程安全
           2 很好滿足靜態分析器要求
           3 和自動引用計數(ARC)兼容 
           4 僅需要少量代碼
    該方法的劣勢就是它仍然運行創建一個非共享的實例:
AccountManager *accountManager = [[AccountManager alloc] init];
    有些時候你希望有這種行爲,但如果正在想要的是僅一個實例被實例化就需要注意這點。
 



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章