在 UIAlertAction 处理程序中更新 UI

Update UI in UIAlertAction handler

你能帮我解决在显示 UIAlertView 实例时更新程序 UI 的问题吗? 情况是这样的:

  1. 我按下工具栏 "hide-button" 并且 alertView 正在打开;
  2. 在 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,谢谢您的指点!