0

我想聲明一個由後臺線程中執行的塊組成的計算屬性。 所以,當我解決這個屬性時,它是零,因爲計算返回沒有準備好的結果。如何更好地糾正這一點?謝謝!如何在計算使用後臺線程時正確聲明計算屬性?

enum Result<T> { 
    case error(error: Error) 
    case success(data: T) 
} 

var userID: Result<CKRecordID>? { 

    var result: Result<CKRecordID>? = nil 

    container.fetchUserRecordID { recordID, error in 
    if let error = error { result = .error(error: error) } 
    if let recordID = recordID { result = .success(data: recordID) } 
    } 

    return result 
} 
+0

難道你不使用閉包?所以當讀取用戶返回時,它會執行一個完成的()封閉並返回記錄ID? – arvidurs

+0

您不能異步返回屬性的值。 –

+5

理論上,您可以應用模式來使其等待響應,但異步檢索機制的整體思想是確保您不會阻止主線程等待某種響應。所以,簡短的答案是,你真的不應該使用計算屬性來包裝一個異步方法。只要堅持'fetchUserRecordID'。如果你想用某種方法把它封裝起來,那麼在完成處理程序閉包中返回你的'Result '類型,這很好,但是不要試圖用一個計算屬性來處理。 – Rob

回答

1

有一個直接的解決方案,比如使用GCD信號量。然而,整個方法首先看起來並不正確,因爲在某些情況下(如在主線程中調用此屬性),這可能會導致不必要的掛起甚至死鎖。更好的方法是將該代碼移至具有適當完成處理程序的方法。

請記住,計算出的屬性並不是要替換方法。如果在範圍中有一些複雜的(尤其是異步的)計算,那麼您幾乎可以將該代碼從屬性移動到方法。

但不管怎麼說:

var userID: Result<CKRecordID>? { 

    var result: Result<CKRecordID>? = nil 

    var sema = DispatchSemaphore(value: 0) 

    container.fetchUserRecordID { recordID, error in 
     if let error = error { result = .error(error: error) } 
     if let recordID = recordID { result = .success(data: recordID) } 

     sema.signal() 
    } 

    _ = sema.wait(timeout: .distantFuture) 

    return result 
} 

這裏有一個GCD信號燈等待其爲異步操作完成。