在 UIAlertAction 处理程序中更新 UI
Posted
技术标签:
【中文标题】在 UIAlertAction 处理程序中更新 UI【英文标题】:Update UI in UIAlertAction handler 【发布时间】:2016-07-22 08:51:37 【问题描述】:您能帮我解决在显示 UIAlertView 实例时更新程序 UI 的问题吗? 情况是这样的:
-
我正在按下工具栏的“隐藏按钮”,并且 alertView 正在打开;
在 UIAlertAction(确定按钮)的处理程序中,我有一个代码,我在其中进行了几个操作:
移除按下的工具栏“隐藏按钮”,改为使用活动指示器设置按钮项;
使指标滚动;
只有在前面的步骤之后,下一部分代码才应该开始并且数据模型正在更新,并且因为它通过 NSFetchedResultsControllerDelegate 连接到 tableView,tableView 的数据将自动更新。此步骤可能需要一些时间,因此非常需要异步保持它,并且在处理它时,活动指示器应该滚动;
在活动指示器滚动出现故障后,工具栏按钮项将被删除,并且“隐藏按钮”(在第一步中删除)又回来了。
完成。
当我交换“隐藏按钮”和“活动按钮”时,问题在于更新 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
如果我不删除指示器按钮,我毕竟可以看到它,但它必须更早出现。我做错了什么? 谢谢!
【问题讨论】:
尝试将你的睡眠从主线程移到你的后台线程。目前你的 sleep 阻塞了主线程,所以 UIKit 不能在它上面做任何事情,它不会在这个时候开始动画。 @PeterK,它有效。我真的可以在 5 秒内观察到滚动并进行任何 UI 操作。今天晚上,我将检查它如何在具有许多记录且没有睡眠功能的真实设备上工作。如果它这么容易解决,你真的是巫师:)我会回应。 所以理论上,如果 sleep(5) 在上面的位置,我会看到活动指示器,以防它是真正的延迟?但5秒后。睡觉?是否可以在 NSFetchedResultsControllerDelegate 方法更新我的表中的行时进行 UI 操作? NSFetchedResultsControllerDelegate 应该异步工作,是的,您可以进行 UI 操作。我不记得了,但如果 NSFetchedResultsControllerDelegate 不能在主线程上工作,你应该在主线程上执行所有 UI 操作。 在第一种情况下,您阻塞了主线程 5 秒,因此任何动画都无法启动,之后您快速执行了一些操作,因此您可能没有注意到任何更改隐藏活动指示器之前的 UI。 【参考方案1】:问题解决了。 这是因为 NSFetchedResultsController 更新了不在主线程中的 UI。在我的模型更新时,我不得不停用它的委托。然后,在主线程中,我必须再次激活它并更新 tableView 数据。解决方案在这里(查看 cmets):
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,感谢您的建议!
【讨论】:
您还可以在每个委托的回调中使用 dispatch_async(dispatch_get_main_queue()) 并为每个委托更改更新 UI,从用户的角度来看,它应该更具响应性。以上是关于在 UIAlertAction 处理程序中更新 UI的主要内容,如果未能解决你的问题,请参考以下文章