什么是單例
單例模式是一種常用的軟件設(shè)計模式。在它的核心結(jié)構(gòu)中只包含一個被稱為單例的特殊類。通過單例模式可以保證系統(tǒng)中一個類只有一個實(shí)例
單例的使用場景
單例的作用是為了整個程序運(yùn)行過程中一個類只會出現(xiàn)一個實(shí)例對象,那么只要符合該要求都可以使用單例來創(chuàng)建。像程序中的用戶
、購物車
,Cocoa Touch框架中使用的單例有NSUserDefaults
、UIApplication
、NSFileManager
。
單例的本質(zhì)
單例模式是要系統(tǒng)中一個類只有一個實(shí)例對象。
那么我們可以在使用該類創(chuàng)建對象時,查看它是否已經(jīng)有存在的對象,如果有,返回該對象。如果沒有,創(chuàng)建一個新的對象并返回。
<1>
static id _user;
+(instancetype)allocWithZone:(struct _NSZone *)zone{
if (_user == nil) {
_user = [super allocWithZone:zone];
}
return _user;
}```
這樣寫看似不存在問題,但是如果有多個線程同時訪問。同時調(diào)用`+(instancetype)allocWithZone:(struct _NSZone *)zone`方法,就會出現(xiàn)存在創(chuàng)建不同對象的問題。安全著想,我們需要給它加把鎖。
<2>
static id _user;
+(instancetype)allocWithZone:(struct _NSZone *)zone{
if (_user == nil) { //避免頻繁加鎖
@synchronized(self) {
if (_user == nil) { //避免重復(fù)創(chuàng)建對象
_user = [super allocWithZone:zone];
}
}
}
return _user;
}```
項(xiàng)目中常見創(chuàng)建單例的方法
第一種,使用dispatch_once
創(chuàng)建,該代碼只會在程序中運(yùn)行一次
<3>
.h文件中給外界一個調(diào)用的方法
+ (instancetype)shareUserTool;
.m中進(jìn)行實(shí)現(xiàn)
+ (instancetype)shareUserTool{
static UserTool *user;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
user = [[UserTool alloc]init];
});
return user;
}```
第二種
<4>
.h文件中給外界一個調(diào)用的方法
- (instancetype)shareUserTool;
.m中進(jìn)行實(shí)現(xiàn)
- (instancetype)shareUserTool{
static UserTool *user;
if (user == nil) {
user = [[UserTool alloc]init];
}
return user;
}```
當(dāng)然,這是在不考慮多線程的時候的做法。如果有此需要請考慮<2>
其他創(chuàng)建單例的方法
1.+(void)load
在程序剛運(yùn)行的時候,類會被加載到內(nèi)存,調(diào)用方法+(void)load
。一個類只會調(diào)用一次,運(yùn)用該特性做單例。
id _user;
// 當(dāng)類內(nèi)加載到運(yùn)行環(huán)境中,就會調(diào)用。一個類只會調(diào)用一次。
+(void)load{
_user = [[self alloc]init];
}
+ (instancetype)shareUserTool{
return _user;
}
安全起見,我們在_user為空的時候才開辟內(nèi)存
+(instancetype)allocWithZone:(struct _NSZone *)zone{
if (_user == nil) {
_user = [super allocWithZone:zone];
}
return _user;
}
2.+ (void)initialize
當(dāng)類第一次被使用的時候,會調(diào)用+ (void)initialize
方法,一個類只會在第一次使用的時候調(diào)用。
id _user;
//第一次使用類的時候會調(diào)用
+ (void)initialize
{
_user = [[self alloc]init];
}
+ (instancetype)shareUserTool{
return _user;
}
安全起見,我們在_user為空的時候才開辟內(nèi)存
+(instancetype)allocWithZone:(struct _NSZone *)zone{
if (_user == nil) {
_user = [super allocWithZone:zone];
}
return _user;
}```
####load跟initialize區(qū)別
load:每個類在加載內(nèi)存的時候都會并只會調(diào)用一次
initialize:子類調(diào)用此方法時,父類也會調(diào)用。
#福利
##使用static修飾的作用:
####1.隱藏,避免外界查詢。
如果是沒有被static修飾過的全局變量,具有全局可見性,可以使用`extern`進(jìn)行全局搜索。如下:
在.m文件中定義一個常量_user
@implementation UserTool
id _user;
@end
在其他文件中查找
// 引用某個全局變量(會在整個全局進(jìn)行搜索_user變量)
extern id _user;
使用`static`修飾過的全局變量,則不會被`extern`查找出來,具有安全性!
####2.改變局部變量生命周期,保持變量內(nèi)容的持久
(void)viewDidLoad {
[super viewDidLoad];
for (int i= 0 ; i < 5; i++) {
[self test];
}
}(void)test{
static int a = 1; //用static修飾過的局部變量,能保證在程序運(yùn)行過程中只有一分內(nèi)存
a++;
NSLog(@"%d",a);
}
####3.默認(rèn)初始化為0
#宏
宏使用\可以添加多行
define Height 10\
5
使用宏判斷開發(fā)環(huán)境是ARC還是MRC
if __has_feature(objc_arc)
// ARC
else
// MRC
endif
傳送門:[常見宏定義][1]
[1]: http://my.oschina.net/leejan97/blog/354904