I'm trying to declare a computed property that consists of a block, executed in the background thread.
So, when I address this property, it's nil, as the computation returns the result when it is not ready. How to better correct this? Thank you!
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
}
There's a straight-forward solution, such as using GCD semaphores. However, the entire approach doesn't seem correct in the first place, for this might cause unwanted hangs or even deadlocks in some circumstances (like calling this property in main thread). The better approach would be moving that code to a method with appropriate completion handler.
Just keep in mind that computed properties are not intended to replace methods. If there are some complex (especially asynchronous) calculations in the scope, you're pretty much set to move that code from a property to a method.
But anyway:
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
}
Here you have a GCD semaphore which awaits for async operation to finish.