我正在使用HanekeSwift检索缓存数据,然后在每次出现视图时将其设置为swipeView中的标签。我的代码检索数据没问题,但由于cache.fetch()
是异步的,当我调用我的方法更新视图时,我的标签设置为nil
。无论如何要告诉swift在加载视图之前等待我的缓存数据?
见下面的代码:
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)
}
}
当我单步执行上面的代码时,它始终显示视图,然后进入缓存块。如何使viewWillAppear()允许updateEntries()完成,并且在执行缓存块之前不返回它?非常感谢![/ p>
更新1:
下面的解决方案工作得很好,我的调用是按照正确的顺序进行的(我在通知块中的print语句在缓存检索后执行),但我的视图只在服务器是的时使用非零值更新标签调用。也许我在通知组中混淆了错误的代码?
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:
另外,当我切换视图时,我在控制台中收到此警告。我想我用上面的代码锁定主线程
“此应用程序正在从后台线程修改自动布局引擎,这可能导致引擎损坏和奇怪的崩溃。这将在将来的版本中导致异常。”
答案 0 :(得分:1)
好的建议大家对此有所帮助。以为我明白了。我需要确保我的缓存块不阻塞主队列。见下面的代码
修改强>
感谢@Rob帮助我做出适当的调整以使这项工作
let dispatchGroup = dispatch_group_create()
dispatch_group_enter(dispatchGroup)
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)
}
dispatch_group_notify(dispatchGroup, dispatch_get_main_queue()) {
print("Retrieved Data")
self.removeProgressHUD()
}
答案 1 :(得分:1)
注意:
因此:
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()
}
}
答案 2 :(得分:0)
以下是您可以暂存加载屏幕的简单示例。我只是创建一个提醒视图,您也可以创建自定义加载指标视图。
let alert = UIAlertController(title: "", message: "please wait ...", preferredStyle: .alert)
override func viewWillAppear(animated: Bool) {
self.present(alert, animated: true, completion: nil)
updateEntries() // updates entries from cache when view appears
}
func updateEntries() {
guard let accessToken = UserDefaults.standard.value(forKey: "accessToken") as? String,
let cachedEntryKey = (accessToken + "food_entries.get") as? String else {
return
}
cache.fetch(key: cachedEntryKey).onSuccess { data in
...
// update value in your UI
alert.dismiss(animated: true, completion: nil)
...
} .onFailure { error in
print(error)
...
// if unsuccessful, call servers to retrieve data, set labels in swipeView to that data
...
}
}
答案 3 :(得分:0)
虽然我完全赞同@ozgur关于从UX角度展示某种加载指示器,但我认为学习如何使用Grand Central Dispatch(Apple的异步等待的原生解决方案)的好处可能会有所帮助你是长期的。
在运行某种类型的完成处理程序之前,您可以使用dispatch_groups
等待代码块完全完成运行。
调度组是一种监视一组块的机制。您的应用程序可以根据您的需要同步或异步监视组中的块。通过扩展,一个组可以用于同步代码,这取决于其他任务的完成。
[...]
调度组会跟踪未完成的块数,并且GCD会保留该组,直到其所有关联的块完成执行。
以下是dispatch_groups
的实例示例:
let dispatchGroup = dispatch_group_create()
dispatch_group_async(dispatchGroup, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
// Run whatever code you need to in here. It will only move to the final
// dispatch_group_notify block once it reaches the end of the block.
}
dispatch_group_notify(dispatchGroup, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
// Code in here only runs once all dispatch_group_async blocks associated
// with the dispatchGroup have finished completely.
}
关于dispatch_groups
的重要部分是,它们允许您同时运行多个异步块,并等待所有异步块在运行最终完成处理程序之前完成。换句话说,您可以根据需要将dispatch_group_async
块与dispatchGroup
关联起来。
如果你想使用加载指示器方法(你应该),你可以运行代码来显示加载指示符,然后进入带有完成处理程序的dispatch_group
以删除加载指示符并加载数据dispatch_group
完成后进入视图。