2016-01-25 12 views
0

我需要執行大量的計算,每次從我的應用程序調用getter時。從getter返回的數據會根據環境而不斷變化,並且必須進行大量計算來計算應該返回的內容。因此,我不希望getter中的代碼在主線程上運行。這是我迄今爲止:重新計算後臺線程中的getter

@interface Calculator() 
@property (nonatomic, strong) dispatch_queue_t calculationThread; 
@end 

- (dispatch_queue_t)calculationThread { 
    if (!_calculationThread) { 
     _calculationThread = dispatch_queue_create("calculation_thread", NULL); 
    } 
    return _calculationThread; 
} 

- (NSArray *)calculation { 
    // perform calculation in calculationThread, which should not be on main thread and be asynchronous 
    return arrayContainingCalculations; 
} 

我基本上想知道如何使用GCD來替換評論。我曾嘗試使用dispatch_queue_t和dispatch_group_notify,但我似乎沒有正確實施它。

+0

異步顧名思義意味着它不會等待你吸氣的代碼返回一個值之前執行。正如Peter所說,您需要爲異步代碼設置某種形式的回調塊或委託。要麼是這樣,要麼你從後臺線程中調用getter。 – Hamish

回答

2

我想用一個回調可能是解決這一問題的最簡單,最有效的解決方案。

這簡直是不可能僅使用單個吸氣做異步計算,而不會阻塞線程,它被稱爲上,如您所願稱爲碼後繼續執行,同時它的計算。

你只需要創建一個新的方法與回調,例如:

-(void) doCalculation:(void(^)(NSArray* result))callback { 
    dispatch_async(self.calculationQueue, ^{ 

     NSArray* result = self.calculation; // make sure this is doing a synchronous calculation. If it's asynchronous, you'll have to use a semaphore (or another callback!). 

     if (callback) { 
      dispatch_async(dispatch_get_main_queue(), ^{ // return to main thread 
       callback(result); 
      }); 
     } 
    }); 
} 

然後,你可以簡單地調用它放在你的主線程像這樣:

[calculator doCalculation:^(NSArray* result) { 
    textView.text = [result[0] stringValue]; // update UI with new info. 
}]; 

這樣你可以輕鬆地將您的結果代碼與對該方法的調用保持一致。

同樣值得注意的是,您的calculationQueue的getter(我將其重命名,因爲當您使用隊列時線程是誤導性的)不是線程安全的。我會建議你使用dispatch_once,使其線程安全:

-(dispatch_queue_t) calculationQueue { 

    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     _calculationQueue = dispatch_queue_create("calculation_queue", DISPATCH_QUEUE_SERIAL); 
    }); 

    return _calculationQueue; 
} 
+0

看起來OP已經檢出,但這是正確的答案 –

1

您可以使用以下命令將其異步放入隊列中。但問題是該方法將立即返回。

dispatch_async(your_queue, ^{ 
    // Code to be executed on background thread 
}); 

你可能想要的是有某種方法calculateWithCompletion的是主叫可以定義一旦完成完成後,你可以調用的模塊。

+0

我想保持接口爲self.calculation如果可能 – RDSpinz

0

正如您在您對Peter的評論中所說的那樣,您想保留它,以便您可以撥打self.calculation並讓您的邏輯得到執行並同步返回計算結果。

但是,因爲您希望避免在此邏輯執行時鎖定UI,所以您希望它在後臺線程上執行。

因此,你應該需要做的是使用dispatch_sync而不是dispatch_asynccalculate方法裏面。

dispatch_sync做什麼是它把一個任務到指定的隊列(包含您的邏輯塊)(也許應該選擇一個global concurrent queue),然後在一個線程你的OS選秀權(而不是主線程執行的任務)。 dispatch_async也是如此,將在您將任務分派到隊列後立即繼續執行,除

dispatch_sync另一方面會阻止當前運行循環中的執行,直到任務返回。

這將讓你在後臺線程上執行您昂貴的邏輯,同時仍然保持同步,這樣就可以繼續使用self.calculation

+0

這隻會在OP調用後臺線程的getter時以*開頭,因爲如果從那裏調用getter,dispatch_sync會阻塞主線程。 – Hamish

+0

啊對了,對不起,你說的對我來說是大腦放屁。 OP有幾個選擇,將整個計算邏輯*以及*調用者包裝在'dispatch_async'中,或者像Peter建議的那樣添加一個回調 –