GCD之用dispatch_once建立單例

 

        單例模式是開發者經常使用的一種設置模式,常見的實現方式爲:在類中編寫名爲 sharedInstance的方法,該方法只會返回全類共用的單例實例,而不會在每次調用時建立新的實例.安全

        常見的作法是:函數

+ (instancetype)sharedUser {
    static User *_sharedInstance = nil;
    @synchronized(self) {
        if (!_sharedInstance) {
            _sharedInstance = [[self alloc] init];
        }
    }
    return _sharedInstance;
}

爲了保證線程安全,上面的代碼把建立代理的代碼包裹在同步塊裏. spa

        相對於上面的實現方式,使用GCD的dispatch_once實現起來更爲容易. 所用到的函數是:線程

     static dispatch_once_t onceToken;代理

     dispatch_once(&onceToken, ^{code

     //  code to be executed oncetoken

     });作用域

        此函數接受的類型爲 dispatch_once_t的特殊函數 token,此外還接受塊參數.對於給定的token來講,該函數保證相關的塊一定會執行,且僅執行一次.首次調用該函數時必然會執行塊中的代碼,最重要的是:次操做徹底是線程安全的!!!須要注意的是:對於只需執行一次的塊來講,每次調用函數時傳入的token必須徹底相同.因此一般將token標記聲明在static或者global做用域裏.開發

    使用GCD實現單例方法以下:字符串

+ (instancetype)sharedUser{
    static User *_shareInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (!_shareInstance) {
            _shareInstance = [[self alloc] init];
        }
    });
    return _shareInstance;
}

使用dispatch_once能夠簡化代碼而且實現線程安全,所以你無需擔憂加鎖或者同步的問題.全部問題都有GCD在底層處理.因爲每次調用時都必須使用徹底相同的token,因此token須要聲明爲static. 把token聲明在static做用內,能夠保證編譯器每次執行shareUser方法時都會複用這個變量,而不會建立新的變量.

    此外,dispatch_once更高效. 他沒有使用重量級的加鎖機制,若是是使用加鎖的話,每次運行代碼前都要獲取鎖,相反 dispatch_once 函數採用原子訪問來查詢token,以判斷對應的代碼是否已經執行過.

    --> 使用 dispathch_once 能夠輕鬆編寫 "只需運行一次的線程安全代碼",能夠輕鬆實現單例.

    --> token 應該聲明在static或者golbal做用域中,這樣的話吧只需執行一次的塊傳給dispatch_once函數時,能夠保證傳進去的token也是相同的.

    附贈一份快速實現單例的 .h 文件

調用以下:

1.導入 Singleton.h文件

2.在類的.h文件中 singleton_h(單例的名字),以User類舉例,單例的名字會自動拼接上 shared

#import <Foundation/Foundation.h>
#import "Singleton.h"
@interface User : NSObject

singleton_h(User);

@end

#import "User.h"

@implementation User

singleton_m(User);

@end

3.調用

User *user =  [User sharedUser];

// ## : 鏈接字符串和參數
#define singleton_h(name) + (instancetype)shared##name;

#if __has_feature(objc_arc) // ARC

#define singleton_m(name) \
static id _instance; \
+ (id)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:(struct _NSZone *)zone \
{ \
    return _instance; \
}

#else // 非ARC

#define singleton_m(name) \
static id _instance; \
+ (id)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; \
} \
\
- (oneway void)release \
{ \
\
} \
\
- (id)autorelease \
{ \
return _instance; \
} \
\
- (id)retain \
{ \
return _instance; \
} \
\
- (NSUInteger)retainCount \
{ \
return 1; \
} \
\
+ (id)copyWithZone:(struct _NSZone *)zone \
{ \
return _instance; \
}

#endif

------------------

  文獻參考:<編寫高質量OSX和iOS代碼的52個有效方法>

相關文章
相關標籤/搜索