How to properly declare a computed property, when

2019-02-20 18:20发布

问题:

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
}

回答1:

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.