当计算使用后台线程时,如何正确声明计算属性?
Posted
技术标签:
【中文标题】当计算使用后台线程时,如何正确声明计算属性?【英文标题】:How to properly declare a computed property, when calculation uses background threads? 【发布时间】:2018-03-17 15:36:24 【问题描述】:我正在尝试声明一个由块组成的计算属性,在后台线程中执行。 所以,当我处理这个属性时,它是 nil,因为计算在它没有准备好时返回结果。如何更好地纠正这个问题?谢谢!
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
【问题讨论】:
你不能用闭包代替吗?那么当 fetch 用户返回时,它会执行一个 completed() 闭包并返回记录 id? 不能从属性异步返回值。 理论上你可以应用模式来让它等待响应,但是异步检索机制的整个想法是确保你不会阻塞主线程等待响应。所以,简短的回答是你真的不应该使用计算属性来包装异步方法。坚持使用fetchUserRecordID
。如果您想将其包装在某个方法中,该方法在完成处理程序闭包中返回您的 Result<T>
类型,那很好,但不要尝试使用计算属性。
罗布是对的。这不是将此类代码放入属性的正确位置。对于并发和多线程,请务必学习GCD(Grand Central Dispatch)主题,以了解如何正确管理后台任务。
【参考方案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 信号量。
【讨论】:
以上是关于当计算使用后台线程时,如何正确声明计算属性?的主要内容,如果未能解决你的问题,请参考以下文章