你好,歡迎來到IOS教程網

 Ios教程網 >> IOS訊息 >> 關於IOS >> GCD下的幾種實現同步的方式

GCD下的幾種實現同步的方式

編輯:關於IOS

GCD多線程下,實現線程同步的方式有如下幾種:

1.串行隊列 2.並行隊列 3.分組 4.信號量

實例: 去網上獲取一張圖片並展示在視圖上. 實現這個需求,可以拆分成兩個任務,一個是去網上獲取圖片,一個是展示在視圖上. 這兩個任務是有關聯的,所以需要同步處理.

下面看這幾種方式如何實現.

一、

1.串行隊列

1.1[GCD相關:]

(1)GCD下的dispatch_queue隊列都是FIFO隊列,都會按照提交到隊列的順序執行.

只是根據隊列的性質,分為<1>串行隊列:用戶隊列、主線程隊列 <2>並行隊列.

(2)同步(dispatch_sync)、異步方式(dispatch_async). 配合串行隊列和並行隊列使用.

1.2同步隊列直接提交兩個任務就可以.

GCD下的幾種實現同步的方式
    // 串形隊列
    dispatch_queue_t serilQueue = dispatch_queue_create("com.quains.myQueue", 0);
    
    //開始時間
    NSDate *startTime = [NSDate date];
    
    
    __block UIImage *image = nil;
    
    //1.先去網上下載圖片
    dispatch_async(serilQueue, ^{
        NSString *urlAsString = @"http://avatar.csdn.net/B/2/2/1_u010013695.jpg";
        NSURL *url = [NSURL URLWithString:urlAsString];
        
        NSError *downloadError = nil;
        
        NSData *imageData = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url] returningResponse:nil error:&amp;downloadError];
        
        if (downloadError == nil &amp;&amp; imageData != nil) {
            image = [[UIImage imageWithData:imageData] retain];
        }
        else if(downloadError != nil){
            NSLog(@"error happened = %@", downloadError);
        }
        else{
            NSLog(@"No data download");
        }
    });
    
    //2.在主線程展示到界面裡
    dispatch_async(serilQueue, ^{
        
        NSLog(@"%@",[NSThread currentThread]);
        
        // 在主線程展示
        dispatch_async(dispatch_get_main_queue(), ^{
        if (image != nil) {
            
            UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
            
            [imageView setImage:image];
            
            [imageView setContentMode:UIViewContentModeScaleAspectFit];
            [self.view addSubview:imageView];
            [imageView release];
            
            NSDate *endTime = [NSDate date];
            NSLog(@"串行異步 completed in %f time", [endTime timeIntervalSinceDate:startTime]);
        }
        else{
            NSLog(@"image isn't downloaded, nothing to display");
        }
        });
        
    });
    
    //3.清理
    dispatch_release(serilQueue);
    [image release];
GCD下的幾種實現同步的方式

注意:

(1) __block變量分配在棧,retain下,防止被回收.

(2)dispatch要手動create和release.

(3)提交到主線程隊列的時候,慎用同步dispatch_sync方法,有可能造成死鎖. 因為主線程隊列是串行隊列,要等隊列裡的任務一個一個執行.所以提交一個任務到隊列,如果用同步方法就會阻塞住主線程,而主線程又要等主線程隊列裡的任務 都執行完才能執行那個剛提交的,所以主線程隊列裡還有其他的任務的話,但他已經被阻塞住了,沒法先完成隊列裡的其他任務,即,最後一個任務也沒機會執行 到,於是造成死鎖.

(4)提交到串行隊列可以用同步方式,也可以用異步方式.

 

2.並行隊列

采用並行隊列的時候,可以采用同步的方式把任務提交到隊列裡去,即可以實現同步的方式

GCD下的幾種實現同步的方式
//新建一個隊列
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    //記時
    NSDate *startTime = [NSDate date];
    
    //加入隊列
    dispatch_async(concurrentQueue, ^{
        __block UIImage *image = nil;
        
        //1.先去網上下載圖片
        dispatch_sync(concurrentQueue, ^{
            NSString *urlAsString = @"http://avatar.csdn.net/B/2/2/1_u010013695.jpg";
            NSURL *url = [NSURL URLWithString:urlAsString];
            
            NSError *downloadError = nil;
            
            NSData *imageData = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url] returningResponse:nil error:&amp;downloadError];
            
            if (downloadError == nil &amp;&amp; imageData != nil) {
                image = [UIImage imageWithData:imageData];
            }
            else if(downloadError != nil){
                NSLog(@"error happened = %@", downloadError);
            }
            else{
                NSLog(@"No data download");
            }
        });
        
        //2.在主線程展示到界面裡
        dispatch_sync(dispatch_get_main_queue(), ^{
            if (image != nil) {
                UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
                [imageView setImage:image];
                
                [imageView setContentMode:UIViewContentModeScaleAspectFit];
                [self.view addSubview:imageView];
                [imageView release];
                
                NSDate *endTime = [NSDate date];
                NSLog(@"並行同步 completed in %f time", [endTime timeIntervalSinceDate:startTime]);
            }
            else{
                NSLog(@"image isn't downloaded, nothing to display");
            }
        });
    });
GCD下的幾種實現同步的方式

兩個同步的任務用一個異步的包起來,提交到並行隊列裡去,即可實現同步的方式.

 

3.使用分組方式

3.1 group本身是將幾個有關聯的任務組合起來,然後提供給開發者一個知道這個group結束的點.

雖然這個只有一個任務,但是可以利用group的結束點,去阻塞線程,從而來實現同步方式.

GCD下的幾種實現同步的方式
dispatch_group_t group = dispatch_group_create();
    
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    NSDate *startTime = [NSDate date];
    
    __block UIImage *image = nil;
    
    dispatch_group_async(group, queue, ^{
        
        //1.先去網上下載圖片
            NSString *urlAsString = @"http://avatar.csdn.net/B/2/2/1_u010013695.jpg";
            NSURL *url = [NSURL URLWithString:urlAsString];
            
            NSError *downloadError = nil;
            
            NSData *imageData = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url] returningResponse:nil error:&amp;downloadError];
            
            if (downloadError == nil &amp;&amp; imageData != nil) {
                image = [[UIImage imageWithData:imageData] retain];
            }
            else if(downloadError != nil){
                NSLog(@"error happened = %@", downloadError);
            }
            else{
                NSLog(@"No data download");
            }
        
        });
    
    // 2.等下載好了再在刷新主線程
    dispatch_group_notify(group, queue, ^{
        
        //在主線程展示到界面裡
        dispatch_async(dispatch_get_main_queue(), ^{
            if (image != nil) {
                UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
                [imageView setImage:image];
                [image release];
                
                [imageView setContentMode:UIViewContentModeScaleAspectFit];
                [self.view addSubview:imageView];
                [imageView release];
                
                NSDate *endTime = [NSDate date];
                NSLog(@"分組同步 completed in %f time", [endTime timeIntervalSinceDate:startTime]);
            }
            else{
                NSLog(@"image isn't downloaded, nothing to display");
            }
        });
        
    });
    
    // 釋放掉
    dispatch_release(group);
GCD下的幾種實現同步的方式

dispatch_group 也要手動創建和釋放.

dispatch_notify()提供了一個知道group什麼時候結束的點. 當然也可以使用dispatch_wait()去阻塞.

 

4.信號量

信號量 和 瑣 的作用差不多,可以用來實現同步的方式.

但是信號量通常用在 允許幾個線程同時訪問一個資源,通過信號量來控制訪問的線程個數.

GCD下的幾種實現同步的方式
// 信號量初始化為1
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    NSDate *startTime = [NSDate date];
    
    __block UIImage *image = nil;
    
    
    //1.先去網上下載圖片
    dispatch_async(queue, ^{
        
        // wait操作-1
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        
        // 開始下載
        NSString *urlAsString = @"http://avatar.csdn.net/B/2/2/1_u010013695.jpg";
        NSURL *url = [NSURL URLWithString:urlAsString];
        
        NSError *downloadError = nil;
        
        NSData *imageData = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url] returningResponse:nil error:&amp;downloadError];
        
        if (downloadError == nil &amp;&amp; imageData != nil) {

            image = [[UIImage imageWithData:imageData] retain];
            //NSLog(@"heap %@", image);
            //NSLog(@"%d",[image retainCount]);
        }
        else if(downloadError != nil){
            NSLog(@"error happened = %@", downloadError);
        }
        else{
            NSLog(@"No data download");
        }

        // signal操作+1
        dispatch_semaphore_signal(semaphore);
    });
    
  
    // 2.等下載好了再在刷新主線程
    dispatch_async(dispatch_get_main_queue(), ^{
        
        // wait操作-1
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        
        if (image != nil) {
            
            UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
            
            [imageView setImage:image];
            NSLog(@"%d",[image retainCount]);
            [image release];
            
            [imageView setContentMode:UIViewContentModeScaleAspectFit];
            [self.view addSubview:imageView];
            [imageView release];
            
            NSDate *endTime = [NSDate date];
            NSLog(@"信號量同步 completed in %f time", [endTime timeIntervalSinceDate:startTime]);
        }
        else{
            NSLog(@"image isn't downloaded, nothing to display");
        }
        
        // signal操作+1
        dispatch_semaphore_signal(semaphore);
    });
GCD下的幾種實現同步的方式

dispatch_wait會阻塞線程並且檢測信號量的值,直到信號量值大於0才會開始往下執行,同時對信號量執行-1操作.

dispatch_signal則是+1操作.

 

二、

以上幾種方式,都是通過阻塞線程的方式去實現同步。

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved