正确的方式来实现DispatchQueue

时间:2018-01-14 22:00:59

标签: swift asynchronous grand-central-dispatch

我正在为一个app项目编写一个简单的缓存框架,并在Closures中使用GCD和DispatchQueues来保存和检索框架中的对象。

编程时,我一次又一次地质疑自己做对与否的方法。这是我正在做的一些例子。我在Swift 4中写作。

在使用以下代码获取对象时:

library(data.table)
dt <- data.table(x=c(1,2,3,NA,5), 
                 y=c(1,1,NA,NA,NA),
                 z=c(NA,NA,NA,NA,NA), 
                 d=c(2,2,2,2,2))

for (col in names(copy(dt))){
    v = var(dt[[col]], na.rm = TRUE)
    if (v == 0 | is.na(v)) dt[, (col) := NULL]
}

我想在方式中使用我的框架,闭包的结果可以直接在app中使用。所以我想在异步后台检索它们之后,我必须&#34;给它们回来&#34;在主队列中。我对这个建议是对的吗?我想知道,因为我在open func get(identifier: String, result:@escaping (NSObject?) -> ()) { MKCacheStorageGlobals.dispatchQueue.async { //Get object from memory if let object = self.storageItems[identifier] { DispatchQueue.main.async { result(object) } return } //Else get object from disk guard let storageHandler = self.storageHandler else { DispatchQueue.main.async { result(nil) } return } do { if let object = try storageHandler.get(identifier: identifier) { self.storageItems[identifier] = object DispatchQueue.main.async { result(object) } return } } catch { print(error.localizedDescription) } DispatchQueue.main.async { result(nil) } } } 部分生成了许多DispatchQueue.main.(a)sync({ ... })代码块。

我感谢各种提示,评论或更好的解决方案!

1 个答案:

答案 0 :(得分:3)

有些无关紧要:通常这种异步代码不应该如此看待它调用结果处理程序的位置。调用者可能不希望结果在主队列上。通常,返回队列是“私有后台队列”(HealthKit),可在对象级别配置(URLSession),可在呼叫站点(大多数Dispatch)配置,或以任何方式(大部分基金会)未受到约束。 UIKit有时会承诺在主队列上调用完成处理程序,但这很不寻常。也就是说,如果你非常肯定每个调用者总是希望结果在主队列上,那很好,你可以保证。这种情况有时迫使人们将结果重新发送回其他队列,这是浪费。

除此之外,你如何清理它?几种方式。首先,这段代码是不必要的:

   guard let storageHandler = self.storageHandler else {
        DispatchQueue.main.async {
            result(nil)
        }
        return
    }

您可以使用optional-chaining在以后的用法中获得相同的结果:

        if let object = try self.storageHandler?.get(identifier: identifier) {

“没有存储处理程序”和“存储处理程序中没有对象”之间的此功能没有区别,因此您可以使它们具有相同的代码路径。

但更强大的解决方法是提取这样的函数:

// Should only be called from MKCacheStorageGlobals.dispatchQueue
private func cacheValue(identifier: String) -> NSObject? {
    do {
        if let object = try self.storageHandler?.get(identifier: identifier) {
            storageItems[identifier] = object
            return object
        }
    } catch {
        print(error.localizedDescription)
    }
    return nil
}

open func get(identifier: String,
              result:@escaping (NSObject?) -> (),
              queue: DispatchQueue = .main) {
    MKCacheStorageGlobals.dispatchQueue.async {
        let value = self.storageItems[identifier] ?? self.cacheValue(identifier: identifier)
        queue.async {
            result(value)
        }
    }
}

这将“获取和缓存值”问题与“调用结果处理程序”问题区分开来,因此您不必将两者混合使用。