Swift:在 View 出现之前从异步调用中检索值

标签 swift asynchronous closures grand-central-dispatch haneke

我使用 HanekeSwift 检索缓存的数据,然后在每次 View 出现时将其设置为 swipeView 中的标签。我的代码检索数据没有问题,但由于 cache.fetch() 是异步的,当我调用我的方法来更新 View 时,我的标签被设置为 nil。无论如何,有没有办法告诉 swift 在加载 View 之前等待我的缓存数据被检索?

参见下面的代码:

override func viewWillAppear(animated: Bool) {
    updateEntries() // updates entries from cache when view appears
}

func updateEntries() {
    guard let accessToken = NSUserDefaults.standardUserDefaults().valueForKey("accessToken") as? String else { return }
    guard let cachedEntryKey = String(accessToken) + "food_entries.get" as? String else { return }
    cache.fetch(key: cachedEntryKey).onSuccess { data in
        ...
        // if successful, set labels in swipeView to data retrieved from cache
        ...
        dispatch_group_leave(dispatchGroup)
    } .onFailure { error in
        print(error)
        ...
        // if unsuccessful, call servers to retrieve data, set labels in swipeView to that data
        ...
        dispatch_group_leave(dispatchGroup)
    }
}

当我单步执行上面的代码时,它总是显示 View ,然后单步进入缓存 block 。如何使 viewWillAppear() 允许 updateEntries() 完成并且在执行缓存 block 之前不返回?提前非常感谢!

更新1:

下面的解决方案工作得很好,我的调用是按正确的顺序进行的(通知 block 中的打印语句在缓存检索后执行),但我的 View 仅在服务器启动时用非零值更新其标签叫。也许我在通知组中添加了错误的代码?

override func viewWillAppear(animated: Bool) {
    self.addProgressHUD()
    updateEntries() // updates entries from cache when view appears
}

func updateEntries() {
    guard let accessToken = NSUserDefaults.standardUserDefaults().valueForKey("accessToken") as? String else { return }
    guard let cachedEntryKey = String(accessToken) + "food_entries.get" as? String else { return }

    let dispatchGroup = dispatch_group_create()
    dispatch_group_enter(dispatchGroup)

    dispatch_group_async(dispatchGroup, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
        cache.fetch(key: cachedEntryKey).onSuccess { data in
            ...
            // if successful, set labels in swipeView to data retrieved from cache
            ...
        } .onFailure { error in
            print(error)
            ...
            // if unsuccessful, call servers to retrieve data, set labels in swipeView to that data
            ...
        }
    }

    dispatch_group_notify(dispatchGroup, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
        print("Retrieved Data")
        self.removeProgressHUD()
    }

}

更新2:

此外,当我切换 View 时,我在控制台中收到此警告。我想我用上面的代码锁定了主线程

“此应用程序正在从后台线程修改自动布局引擎,这可能会导致引擎损坏和奇怪的崩溃。这将在将来的版本中导致异常。”

最佳答案

注意:

  • 调用异步方法之前进入组
  • 离开组是每个相应的完成/失败处理程序
  • 将通知 block 中的 UI 更新调度到队列

因此:

func updateEntries() {
    guard let accessToken = NSUserDefaults.standardUserDefaults().valueForKey("accessToken") as? String else { return }
    guard let cachedEntryKey = String(accessToken) + "food_entries.get" as? String else { return }

    let group = dispatch_group_create()
    dispatch_group_enter(group)

    cache.fetch(key: cachedEntryKey).onSuccess { data in
        ...
        // if successful, set labels in swipeView to data retrieved from cache
        ...
        dispatch_group_leave(group)
    } .onFailure { error in
        print(error)
        ...
        // if unsuccessful, call servers to retrieve data, set labels in swipeView to that data
        ...
        dispatch_group_leave(group)
    }

    dispatch_group_notify(group, dispatch_get_main_queue()) {
        print("Retrieved Data")
        self.removeProgressHUD()
    }

}

关于Swift:在 View 出现之前从异步调用中检索值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39323035/

相关文章:

ios - 通过按返回按钮在 UI 文本字段中输入文本

java - 在新线程问题中使用 spring 发送电子邮件

javascript - 变量被绑定(bind)到 getCurrentLocation 函数的回调。为什么这个关闭不起作用?

Javascript 闭包和变量作用域

ios - Today Widget 在 IOS 低于 10 的设备上太大了

ios - 台风参数注入(inject)与初始化器崩溃应用程序

ios - 如何在后台触发多步api交易?

javascript - 将对象引用传递给 javascript 异步函数,但得到了意外的值

javascript - 不确定为什么表单没有加载到已加载的 html 标签上?

Javascript - 无法理解闭包