3

說我要實現像這樣的模式:執行同步操作

a = some array I download from the internet 
b = manipulate a somehow (long operation) 
c = first object of b 

這些顯然需要被同步調用,這是造成在目的C.我的問題,我讀過有關NSOperationQueue和GCD,我不太瞭解它們,或者在這裏適合。有人可以提出一個解決方案嗎?我知道我也可以使用performSelector:@selector(sel)WaitUntilDone,但這對於較大的操作似乎並不高效。

回答

5

因此,創建一個串行調度隊列,將所有工作(每個都在一個塊中)轉儲,最後一個塊在主隊列上發回一個方法,告訴控制類工作完成。

這是迄今爲止最完美的體系結構。

2

我很高興你的問題得到解答。一對夫婦的補充意見:

  1. 在您的術語A小調細化,但我假設你希望異步運行這些任務(即不阻塞主隊列和凍結用戶界面),但你希望這些操作以串行方式進行(即,每個人在開始下一個任務之前都將等待前一步完成)。

  2. 最簡單的方法,之前我潛入串行隊列,是剛做這三個在一個單一的派遣任務:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
        [self doDownloadSynchronously]; 
        [self manipulateResultOfDownload]; 
        [self doSomethingWithFirstObject]; 
    }); 
    

    正如你所看到的,因爲這是所有正在運行的這三個單任務你可以真正將它分派給任何後臺隊列(在上面,這是全局後臺隊列之一),但是因爲你在給定的分派塊內完成了這些,所以這三個步驟將按順序,一個之後。

    請注意,儘管創建同步網絡請求通常是不明智的,但只要您在後臺隊列上執行此操作,問題就不會那麼嚴重(儘管您可能希望創建一個基於操作的網絡請求,如下面所討論的那樣#5如果你想享受取消正在進行的網絡請求的能力)。

  3. 如果您確實需要分別調度這三個任務,那麼只需創建您自己的專用串行隊列。默認情況下,當你創建自己的自定義調度隊列,它是一個串行隊列,如:

    dispatch_queue_t queue = dispatch_queue_create("com.company.app.queuename", 0); 
    

    可以安排這三個任務:

    dispatch_async(queue, ^{ 
        [self doDownloadSynchronously]; 
    }); 
    
    dispatch_async(queue, ^{ 
        [self manipulateResultOfDownload]; 
    }); 
    
    dispatch_async(queue, ^{ 
        [self doSomethingWithFirstObject]; 
    }); 
    
  4. 操作隊列的做法是一樣容易,但默認情況下,操作隊列是併發的,所以如果我們希望它是一個串行隊列,我們​​必須指定不存在併發操作(即最大併發操作數爲1):

    NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 
    queue.maxConcurrentOperationCount = 1; 
    
    [queue addOperationWithBlock:^{ 
        [self doDownloadSynchronously]; 
    }]; 
    
    [queue addOperationWithBlock:^{ 
        [self manipulateResultOfDownload]; 
    }]; 
    
    [queue addOperationWithBlock:^{ 
        [self doSomethingWithFirstObject]; 
    }]; 
    

    這引出了你爲什麼可能在GCD方法中使用操作隊列方法的問題。主要原因是,如果您需要取消操作的能力(例如,如果用戶放棄啓動異步操作的視圖控制器,您可能會停止操作),操作隊列提供了取消操作的能力,但它更麻煩在GCD任務中這樣做。

  5. 在我看來,這裏唯一棘手/微妙的問題是,您希望如何同步執行網絡操作。您可以使用NSURLConnection分類方法sendSynchronousRequest或僅使用dataWithContentsOfURL從服務器獲取NSData。使用這些類型的同步網絡請求存在限制(例如,一旦啓動請求就無法取消請求),所以我們很多人都會使用基於NSOperation的網絡請求。

    這樣做是正確的可能是超出你的問題的範圍,所以我可能會建議您可以考慮使用AFNetworking創建它,你可以在上述溶液#4集成了一個基於操作的網絡請求,消除急需的編程如果你自己做了NSOperation的網絡操作。

  6. 要記住的主要原因是,當您在後臺隊列上運行這類代碼時,當您需要執行UI更新(或更新模型)時,這些代碼必須返回到主隊列中,不是背景排隊。因此,如果做一個GCD的實現,你會怎麼做:

    dispatch_async(queue, ^{ 
        [self doSomethingWithFirstObject]; 
    
        dispatch_async(dispatch_get_main_queue(),^{ 
         // update your UI here 
        }); 
    }); 
    

    等效NSOperationQueue翻譯是:

    [queue addOperationWithBlock:^{ 
        [self doSomethingWithFirstObject]; 
    
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 
         // update your UI here 
        }]; 
    }]; 
    

本質上引這些問題是Concurrency Programming Guide

有一噸的偉大的WWDC視頻的話題,包括WWDC 2012的視頻Asynchronous Design Patterns with Blocks, GCD, and XPCBuilding Concurrent User Interfaces on iOS和WWDC 2011視頻Blocks and Grand Central Dispatch in PracticeMastering Grand Central Dispatch

+0

哇!非常感謝這個迴應,我打算把它打印出來,然後帶着我一起去咖啡店!對此,我真的非常感激!看起來像NSOperationQueue是超級簡單易用! – JoshDG