主隊列上的同步異步執(zhí)行
-
主隊列 異步執(zhí)行 在主線程有序執(zhí)行
dispatch_queue_t queue = dispatch_get_main_queue();
for (int i = 0; i < 10; i++) {dispatch_async(queue, ^{ NSLog(@"hello---%d %@",i,[NSThread currentThread]); }); }

-
主隊列 同步執(zhí)行 在主線程上執(zhí)行時會死鎖
dispatch_queue_t queue = dispatch_get_main_queue(); //測試執(zhí)行 NSLog(@"begin"); for (int i = 0; i < 10; i++) { dispatch_sync(queue, ^{ NSLog(@"hello --- %@",[NSThread currentThread]); }); } //測試執(zhí)行 NSLog(@"end");

分析
從運行結果可以明顯看出,程序無法正常執(zhí)行 被死鎖。
接下來看一下鎖死的原因:
當程序運行到下面這段代碼時
<pre> dispatch_sync(queue, ^{
NSLog(@"hello --- %@",[NSThread currentThread]);
}); </pre>
主線程:如果主線程正在執(zhí)行行代碼,就不調度任務
同步執(zhí)行: 如果第一個任務沒有執(zhí)行,就等待第一個任務執(zhí)行完成后,在執(zhí)行下一個任務。導致程序互相等待,造成死鎖。
解決方案
(主隊列 同步執(zhí)行)放入異步執(zhí)行,解決死鎖問題
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_queue_t queue1 = dispatch_get_global_queue(0, 0);
//測試執(zhí)行
NSLog(@"begin");
dispatch_async(queue1, ^{
for (int i = 0; i <10; i++) {
dispatch_sync(queue, ^{
NSLog(@"hello---%d %@",i,[NSThread currentThread]);
});
}
});
//測試執(zhí)行
NSLog(@"end");

知識拓展
主隊列于串行隊列的區(qū)別
- 串行隊列: 必須的一個任務調度完成,再去執(zhí)行另一個任務
- 主隊列: 以先進先出的調度任務,如果主線程上有任務在執(zhí)行,主隊列不會調用任務
走進NSOperation
NSOperation是一個抽象的類
- 不能直接使用(方法沒有實現(xiàn))
- 結束子類都具有共同的屬性和方法
NSOperation的子類
- NSInvocationOperation
- NSBlockOperation
- 自定義operation
NSOperationQueue隊列
-
NSInvocationOperation
新建一個NSInvocationOperation對象
- (id)initWithTarget:(id)target selector:(SEL)sel object:(nullable id)arg;
- 調用start方法開始執(zhí)行操作
- (void) start;
一旦執(zhí)行操作,就回到用start 的sel方法
注意
默認情況下,調用start方法并不會開一條新線程執(zhí)行操作,而是在當前線程同步執(zhí)行操作,只有將一個NSOperation放到NSOperationQueue中,才會異步執(zhí)行操作
接下來我們來測試一下
- (void)viewDidLoad {
[super viewDidLoad];
//NSInvocationOperation操作
//創(chuàng)建操作
NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(diown) object:nil];
//創(chuàng)建隊列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//異步執(zhí)行
[queue addOperation:operation];
//同步執(zhí)行
}
-(void) diown{
NSLog(@"download --- %@",[NSThread currentThread]);
}

可以看出,在子線程中執(zhí)行的。如果沒有將NSOperation放到NSOperationQueue中,將會同步執(zhí)行,這里不做演示了
-
NSBlockOperation
新建一個 NSBlockOperation對象
+ (instancetype)blockOperationWithBlock:(void (^)(void))block;
*創(chuàng)建addExecutionBlock:方法添加更多操作
- (void)addExecutionBlock:(void (^)(void))block;
注意
只要NSBlockOperation封裝的操作 >1 就會執(zhí)行,異步操作
接下來我們來測試一下
NSBlockOperation *operation = [[NSBlockOperation alloc]init];
[operation addExecutionBlock:^{
NSLog(@"----下載圖片--1---%@",[NSThread currentThread]);
}];
[operation addExecutionBlock:^{
NSLog(@"----下載圖片--2---%@",[NSThread currentThread]);
}];
[operation start];

-
NSOperationQueue
NSOperationQueue的作用
NSOperation可以調用start方法來調用任務,但是默認是同步執(zhí)行。如果將NSOperation添加到NSOperationQueue的隊列中,系統(tǒng)會自動,異步執(zhí)行
添加操作到NSOperationQueue中
- (void)addOperation:(NSOperation *)op;
- (void)addOperationWithBlock:(void (^)(void))block ;
下面將演示這兩種不同的添加方式
- 第一種
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
NSInvocationOperation *op = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(deom) object:nil];
[op start];
[queue addOperation:op];
- (void) demo{
NSLog(@"%@",[NSThread currentThread]);
}
- 第二種(創(chuàng)建全程隊列)--相比第一種,這一種更為簡便
@interface ViewController ()
//創(chuàng)建一個全程隊列
@property (nonatomic, strong) NSOperationQueue *queue;
@end
//懶加載
- (NSOperationQueue *)queue{
if (_queue == nil) {
_queue = [[NSOperationQueue alloc]init];
}
return _queue;
}
[self.queue addOperationWithBlock:^{
NSLog(@"qqq %@",[NSThread currentThread]);
NSLog(@"下載圖片");
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"回到主線程");
NSLog(@"%@",[NSThread currentThread]);
}];
}];