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信号灯等待其为异步操作完成。