在 UIAlertAction 处理程序中更新 UI
Update UI in UIAlertAction handler
你能帮我解决在显示 UIAlertView 实例时更新程序 UI 的问题吗?
情况是这样的:
- 我按下工具栏 "hide-button" 并且 alertView 正在打开;
- 在 UIAlertAction(确定按钮)的处理程序中,我有一段代码,我在其中进行了多项操作:
- 删除工具栏 "hide-button" 按下并设置带有 activity 指示符的按钮项;
- 使指标滚动;
- 然后并且仅在前面的步骤之后,下一部分代码应该开始并且正在更新数据模型,并且因为它通过 NSFetchedResultsControllerDelegate 连接到 tableView,tableView 的数据将自动更新。此步骤可能需要一些时间,因此非常需要异步保持它,并且在处理它时 activity 指标应该滚动;
- 在 activity 指示器滚动故障之后,带有它的工具栏按钮项目被删除,"hide-button"(在第一步删除)又回来了。
完成。
当我交换 "hide-button" 和 "activity-button" 时,问题在于更新 UI。
private var hideDataBarButtonItem: UIBarButtonItem?
private var indicatorBarButtonItem = UIBarButtonItem(customView: UIActivityIndicatorView(activityIndicatorStyle: .Gray))
override func viewDidLoad() {
super.viewDidLoad()
...
hideDataBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Stop, target: self, action: #selector(hideAllLoginData))
toolbarItems?.insert(hideDataBarButtonItem!, atIndex: 2)
}
这是 hideDataBarButtonItem 的操作:
@IBAction func hideAllLoginData(sender: AnyObject) {
let confirmAlert = UIAlertController(title: "Hide all data?", message: "", preferredStyle: .Alert)
confirmAlert.addAction( UIAlertAction(title: "OK", style: .Default, handler: { action in
// remove the clear-button, set the indicator button instead and start indicator rolling
self.toolbarItems?.removeAtIndex(2)
self.toolbarItems?.insert(self.indicatorBarButtonItem, atIndex: 2)
(self.indicatorBarButtonItem.customView as! UIActivityIndicatorView).startAnimating()
print("button with indicator added")
sleep(5) // -> CHECK: this moment indicator should be visible and rolling!
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)) {
for section in self.resources {
for resource in section {
if resource.defRecord != nil {
resource.defRecord = nil
}
}
}
print("data cleared")
dispatch_async(dispatch_get_main_queue()) {
// remove indicator and set the clear-button back
print("button with indicator removed")
(self.indicatorBarButtonItem.customView as! UIActivityIndicatorView).stopAnimating()
self.toolbarItems?.removeAtIndex(2)
self.toolbarItems?.insert(self.hideDataBarButtonItem!, atIndex: 2)
}
}
}) )
confirmAlert.addAction( UIAlertAction(title: "Cancel", style: .Cancel, handler: nil ) )
self.presentViewController(confirmAlert, animated: true, completion: nil)
}
执行结果:
button with indicator added
// -> 5 sec of awaiting, but that's nothing in interface changed!
data cleared
button with indicator removed
如果我不删除指示按钮,我仍然可以看到它,但它必须更早出现。我做错了什么?
谢谢!
问题已解决。
这是因为 NSFetchedResultsController 更新了 UI 不在主线程中。在我的模型更新时,我不得不停用它的委托。然后,在主线程中我必须再次激活它并更新 tableView 数据。解决方法在这里(看评论):
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)) {
// clear the delegate in order to not to allow UI update by fetchedResultsController
self.resourceModel.nullifyFetchedResultsControllerDelegate()
for section in self.resources {
for resource in section {
if resource.defRecord != nil {
resource.defRecord = nil
}
}
}
print("data cleared")
dispatch_async(dispatch_get_main_queue()) {
// set the delegate back and update the tableView
self.resourceModel.setFetchedResultsControllerDelegate(self)
self.reloadResources()
self.tableView.reloadData()
// remove indicator and set the clear-button back
print("button with indicator removed")
(self.indicatorBarButtonItem.customView as! UIActivityIndicatorView).stopAnimating()
self.toolbarItems?.removeAtIndex(2)
self.toolbarItems?.insert(self.hideDataBarButtonItem!, atIndex: 2)
}
}
PeterK,谢谢您的指点!
你能帮我解决在显示 UIAlertView 实例时更新程序 UI 的问题吗? 情况是这样的:
- 我按下工具栏 "hide-button" 并且 alertView 正在打开;
- 在 UIAlertAction(确定按钮)的处理程序中,我有一段代码,我在其中进行了多项操作:
- 删除工具栏 "hide-button" 按下并设置带有 activity 指示符的按钮项;
- 使指标滚动;
- 然后并且仅在前面的步骤之后,下一部分代码应该开始并且正在更新数据模型,并且因为它通过 NSFetchedResultsControllerDelegate 连接到 tableView,tableView 的数据将自动更新。此步骤可能需要一些时间,因此非常需要异步保持它,并且在处理它时 activity 指标应该滚动;
- 在 activity 指示器滚动故障之后,带有它的工具栏按钮项目被删除,"hide-button"(在第一步删除)又回来了。 完成。
当我交换 "hide-button" 和 "activity-button" 时,问题在于更新 UI。
private var hideDataBarButtonItem: UIBarButtonItem?
private var indicatorBarButtonItem = UIBarButtonItem(customView: UIActivityIndicatorView(activityIndicatorStyle: .Gray))
override func viewDidLoad() {
super.viewDidLoad()
...
hideDataBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Stop, target: self, action: #selector(hideAllLoginData))
toolbarItems?.insert(hideDataBarButtonItem!, atIndex: 2)
}
这是 hideDataBarButtonItem 的操作:
@IBAction func hideAllLoginData(sender: AnyObject) {
let confirmAlert = UIAlertController(title: "Hide all data?", message: "", preferredStyle: .Alert)
confirmAlert.addAction( UIAlertAction(title: "OK", style: .Default, handler: { action in
// remove the clear-button, set the indicator button instead and start indicator rolling
self.toolbarItems?.removeAtIndex(2)
self.toolbarItems?.insert(self.indicatorBarButtonItem, atIndex: 2)
(self.indicatorBarButtonItem.customView as! UIActivityIndicatorView).startAnimating()
print("button with indicator added")
sleep(5) // -> CHECK: this moment indicator should be visible and rolling!
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)) {
for section in self.resources {
for resource in section {
if resource.defRecord != nil {
resource.defRecord = nil
}
}
}
print("data cleared")
dispatch_async(dispatch_get_main_queue()) {
// remove indicator and set the clear-button back
print("button with indicator removed")
(self.indicatorBarButtonItem.customView as! UIActivityIndicatorView).stopAnimating()
self.toolbarItems?.removeAtIndex(2)
self.toolbarItems?.insert(self.hideDataBarButtonItem!, atIndex: 2)
}
}
}) )
confirmAlert.addAction( UIAlertAction(title: "Cancel", style: .Cancel, handler: nil ) )
self.presentViewController(confirmAlert, animated: true, completion: nil)
}
执行结果:
button with indicator added
// -> 5 sec of awaiting, but that's nothing in interface changed!
data cleared
button with indicator removed
如果我不删除指示按钮,我仍然可以看到它,但它必须更早出现。我做错了什么? 谢谢!
问题已解决。 这是因为 NSFetchedResultsController 更新了 UI 不在主线程中。在我的模型更新时,我不得不停用它的委托。然后,在主线程中我必须再次激活它并更新 tableView 数据。解决方法在这里(看评论):
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)) {
// clear the delegate in order to not to allow UI update by fetchedResultsController
self.resourceModel.nullifyFetchedResultsControllerDelegate()
for section in self.resources {
for resource in section {
if resource.defRecord != nil {
resource.defRecord = nil
}
}
}
print("data cleared")
dispatch_async(dispatch_get_main_queue()) {
// set the delegate back and update the tableView
self.resourceModel.setFetchedResultsControllerDelegate(self)
self.reloadResources()
self.tableView.reloadData()
// remove indicator and set the clear-button back
print("button with indicator removed")
(self.indicatorBarButtonItem.customView as! UIActivityIndicatorView).stopAnimating()
self.toolbarItems?.removeAtIndex(2)
self.toolbarItems?.insert(self.hideDataBarButtonItem!, atIndex: 2)
}
}
PeterK,谢谢您的指点!