当计算使用后台线程时,如何正确声明计算属性?

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&lt;T&gt; 类型,那很好,但不要尝试使用计算属性。 罗布是对的。这不是将此类代码放入属性的正确位置。对于并发和多线程,请务必学习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 信号量。

【讨论】:

以上是关于当计算使用后台线程时,如何正确声明计算属性?的主要内容,如果未能解决你的问题,请参考以下文章

Vuejs2:数组更改时如何重新渲染数组计算属性

ThreadLocal的正确使用与原理

如何让MATLAB充分利用计算机资源进行计算

Python中类的声明,使用,属性,实例属性,计算属性及继承,重写

vue计算属性内容分发

Vue的computed和watch的使用和区别