利用操作隊(duì)列和信號(hào)量來(lái)實(shí)現(xiàn)操作同步
最近在開(kāi)發(fā)iOS過(guò)程中遇到一個(gè)問(wèn)題:某一些操作需要在一個(gè)初始化操作后才允許執(zhí)行。但是這些操作的執(zhí)行時(shí)刻有可能比初始化操作來(lái)得要快。那么,如果不等待初始化操作后再執(zhí)行的話(huà),這些操作就等于是丟失了。
針對(duì)這個(gè)問(wèn)題,我想到了兩種解決方案:***就是執(zhí)行這些操作之前先判斷是否已經(jīng)初始化,如果尚未初始化則使用一個(gè)數(shù)組隊(duì)列把操作參數(shù)及調(diào)用的方法存儲(chǔ)起來(lái),等待初始化完成后再檢測(cè)數(shù)組隊(duì)列中的保存的操作進(jìn)行調(diào)用并清空隊(duì)列。但這種方式有個(gè)問(wèn)題就是操作中傳遞的參數(shù)以及調(diào)用方法引用都需要自己來(lái)維護(hù),這無(wú)疑是給自己帶來(lái)了一定的工作量以及風(fēng)險(xiǎn),稍有不慎就有可能會(huì)導(dǎo)致內(nèi)存泄露。
因此第二中解決方法就是利用串行隊(duì)列結(jié)合信號(hào)量的方式來(lái)控制操作的執(zhí)行。此方案的思路是,先創(chuàng)建一條串行隊(duì)列,此隊(duì)列用于執(zhí)行所有的操作。但是***入隊(duì)的是一個(gè)等待信號(hào)的操作。而這個(gè)信號(hào)的初始值是0,直到初始化操作完成后才會(huì)發(fā)送一個(gè)信號(hào)來(lái)通知此操作。因此,在尚未初始化完成的時(shí)候此隊(duì)列是一直處于阻塞狀態(tài)的。所以到有操作進(jìn)入隊(duì)列時(shí)都會(huì)立刻執(zhí)行,而是需要等到初始化信號(hào)過(guò)來(lái)后才開(kāi)始執(zhí)行。
為了驗(yàn)證這一想法,我新建了一個(gè)應(yīng)用工程,在ViewController中定義了操作隊(duì)列_quque和信號(hào)量_sema,如下:
- @interface ViewController : UIViewController
- {
- @private
- dispatch_queue_t _queue;
- dispatch_semaphore_t _sema;
- }
- @end
初始化時(shí)創(chuàng)建操作隊(duì)列
- - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
- {
- if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])
- {
- _queue = dispatch_queue_create("cn.vimfung.demo", DISPATCH_QUEUE_SERIAL);
- }
- return self;
- }
在ViewController中定義了三個(gè)按鈕,分別為DoSomething、Signal、Wait。其中DoSomething為執(zhí)行的操作。Signal為通知阻塞隊(duì)列可以執(zhí)行操作了。Wait為阻塞當(dāng)前隊(duì)列。
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- // Do any additional setup after loading the view, typically from a nib.
- UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
- [btn setTitle:@"DoSomething" forState:UIControlStateNormal];
- [btn sizeToFit];
- [btn addTarget:self action:@selector(doSomethingHandler:) forControlEvents:UIControlEventTouchUpInside];
- [self.view addSubview:btn];
- UIButton *btn1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
- [btn1 setTitle:@"Signal" forState:UIControlStateNormal];
- [btn1 sizeToFit];
- [btn1 addTarget:self action:@selector(signalHanlder:) forControlEvents:UIControlEventTouchUpInside];
- btn1.frame = CGRectMake(0.0, 50.0, btn1.frame.size.width, btn1.frame.size.height);
- [self.view addSubview:btn1];
- UIButton *btn2 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
- [btn2 setTitle:@"Wait" forState:UIControlStateNormal];
- [btn2 sizeToFit];
- [btn2 addTarget:self action:@selector(waitHanlder:) forControlEvents:UIControlEventTouchUpInside];
- btn2.frame = CGRectMake(0.0, 100.0, btn2.frame.size.width, btn2.frame.size.height);
- [self.view addSubview:btn2];
- }
- - (void)doSomethingHandler:(id)sender
- {
- dispatch_async(_queue, ^{
- NSLog(@"do something");
- });
- }
- - (void)signalHanlder:(id)sender
- {
- dispatch_semaphore_signal(_sema);
- }
- - (void)waitHanlder:(id)sender
- {
- if (_sema)
- {
- dispatch_release(_sema);
- }
- _sema = dispatch_semaphore_create(0);
- dispatch_async(_queue, ^{
- dispatch_semaphore_wait(_sema, DISPATCH_TIME_FOREVER);
- });
- }
運(yùn)行后,先點(diǎn)擊Wait讓隊(duì)列阻塞、然后這時(shí)無(wú)論怎么點(diǎn)擊DoSomething都是不會(huì)有l(wèi)og信息顯示,直到點(diǎn)擊Signal后,之前點(diǎn)擊的DoSomething將會(huì)一一打印出來(lái)信息。
可見(jiàn)這種解決方案是可行的,并且可以更加容易操作。























