在我認(rèn)為單例最大的優(yōu)點(diǎn)就是:通過(guò)單例方式訪問(wèn)的實(shí)例,都是同一個(gè)。
這個(gè)優(yōu)點(diǎn)也是我在藍(lán)牙音樂(lè)盒項(xiàng)目中使用單例模式實(shí)現(xiàn)外設(shè)控制類(lèi)和AVFoundation類(lèi)的原因。
你們想,假設(shè)我在a,b,c頁(yè)面都會(huì)調(diào)用到_player,那么我再a頁(yè)面點(diǎn)擊播放、上一首、下一首等等操作后,怎么讓b,c頁(yè)面知道并同步呢?我一開(kāi)始使用的是通知??墒俏以嚵撕蟀l(fā)現(xiàn),最好的還是單例。
單例模式下的無(wú)論在那個(gè)類(lèi)訪問(wèn)_player實(shí)例,它的狀態(tài)都是最新的,也就是a點(diǎn)了播放,那么我在b,c頁(yè)面訪問(wèn)_play實(shí)例,就可以知道它的狀態(tài)是播放的,不需要通知。
創(chuàng)建單例:
.h
+ (CustomObject *)share;
.m
+ (CustomObject *)share{
static CustomObject *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[CustomObject alloc] init];
});
return instance;
}
代碼解釋?zhuān)?a href="http://www.itdecent.cn/p/9607067e186c" target="_blank">鏈接
dispatch_once主要根據(jù)onceToken的值來(lái)決定是否執(zhí)行block里的方法,如果onceToken==0,線程執(zhí)行block里的方法,當(dāng)onceToken==-1,線程不執(zhí)行block。當(dāng)onceToken為其他值時(shí),線程被阻塞,等待onceToken值改變。
當(dāng)線程首先調(diào)用instance,某一線程要執(zhí)行block中的代碼時(shí),首先需要改變onceToken的值,再去執(zhí)行block中的代碼。這里onceToken的值變?yōu)榱?40734731430192。這樣當(dāng)其他線程再獲取onceToken的值時(shí),值已經(jīng)變?yōu)?40734731430192。其他線程被阻塞。當(dāng)block線程執(zhí)行完block之后。onceToken變?yōu)?1。其他線程不再阻塞,跳過(guò)block。下次再調(diào)用shareInstance時(shí),block已經(jīng)為-1。直接跳過(guò)block。這樣dispatch_once在首次調(diào)用時(shí)同步阻塞線程,生成單例之后,不再阻塞線程。dispatch_once是創(chuàng)建單例的最優(yōu)方案
通過(guò)下面代碼可以理解單例的優(yōu)點(diǎn):
viewController.m
- (void)viewDidLoad {
[super viewDidLoad];
CustomObject *cv = [CustomObject share];
cv.tempString = @"123";
}
SecondView.m
- (void)viewDidLoad {
[super viewDidLoad];
CustomObject *cv = [CustomObject share];
NSLog(@"%@",cv.tempString);
}
CocoaPodsDemo[87052:9724995] 123
可以看到:
1.獲取CustomObject對(duì)象的實(shí)例很方便。
2.在兩個(gè)類(lèi)里的實(shí)例變量實(shí)際上是同一個(gè),沒(méi)有重新alloc空間,節(jié)省了內(nèi)存。當(dāng)然,通過(guò)單例創(chuàng)建的實(shí)例常駐內(nèi)存,所以資源開(kāi)銷(xiāo)就見(jiàn)仁見(jiàn)智。
3.獲取實(shí)例的狀態(tài)非常容易。因?yàn)槭峭粋€(gè)實(shí)例,當(dāng)我在第一個(gè)類(lèi)里改變了tempString狀態(tài)為@"123",我再第二個(gè)類(lèi)想要獲取tempString的狀態(tài)馬上就變成了@"123"。
第三條原因讓單例使用起來(lái)非常爽,也是我認(rèn)為單例最大的優(yōu)點(diǎn),這我一開(kāi)始就說(shuō)過(guò)了。
注意:
訪問(wèn)單例類(lèi)一定要通過(guò)定義的單例方法+ (CustomObject *)share。如果依舊使用alloc、init或者new就會(huì)發(fā)生下面的情況
viewController.h
- (void)viewDidLoad {
[super viewDidLoad];
CustomObject *cv = [CustomObject share];
cv.tempString = @"123";
}
SecondView.h
- (void)viewDidLoad {
[super viewDidLoad];
CustomObject *cv = [[CustomObject alloc] init];
NSLog(@"%@",cv.tempString);
}
CocoaPodsDemo[87052:9724995] (null)
解釋?zhuān)?br> 上面兩個(gè)類(lèi)里獲得的實(shí)例其實(shí)不是同一個(gè),因?yàn)橥ㄟ^(guò)單例方式獲得實(shí)例本來(lái)就是通過(guò)封鎖alloc init方法實(shí)現(xiàn)的,但是我再SecondView重新使用了alloc/init方法實(shí)例化了。
那么如何避免呢?下面是我想的一種方法,希望指點(diǎn):
- (instancetype)init{
return [CustomObject share];
}
- (instancetype)initHidden{
self = [super init];
if (self) {
}
return self;
}
+ (CustomObject *)share{
static CustomObject *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[CustomObject alloc] initHidden];
});
return instance;
}