iOS驳回UIAlertController以响应事件

时间:2022-08-19 00:04:29

I have a situation where I want to present a UIAlertController in order to wait for an event (asynchronous request for data from third party) to finish before showing my main ViewController to the user to interact with.

我有一种情况,我想要显示一个UIAlertController,以便等待一个事件(从第三方获取数据的异步请求)结束,然后向用户显示我的主视图控制器以进行交互。

Once the asynchronous code finishes, then I want to dismiss the UIAlertController. I know that normally UIAlertControllers are setup with a button to dismiss it, which is input from the user. I am wondering if what I want to do (dismiss with an event instead of user input) is possible?

异步代码完成后,我想取消UIAlertController。我知道通常uialertcontroller会设置一个按钮来关闭它,这是用户的输入。我想知道我想做什么(用事件而不是用户输入来取消)是可能的吗?

So far, I tried to show the UIAlertController, and then wait in a while loop checking a boolean for when the event occurs:

到目前为止,我试图显示UIAlertController,然后在while循环中等待,检查事件发生时的布尔值:

var alert = UIAlertController(title: "Please wait", message: "Retrieving data", preferredStyle: UIAlertControllerStyle.Alert)

self.presentViewController(alert, animated: true, completion: nil)

// dataLoadingDone is the boolean to check   
while (!dataLoadingDone) {

}

self.dismissViewControllerAnimated(true, completion: nil)

This gives a warning

这给了一个警告

Warning: Attempt to dismiss from view controller while a presentation or dismiss is in progress!

警告:当演示或取消正在进行时,尝试从视图控制器中取消!

and does not dismiss the UIAlertController. I also tried alert.dismissViewControllerAnimated(true, completion: nil) instead of self.dismissViewControllerAnimated(true, completion: nil), but this doesn't get rid of the UIAlertController either.

不解散UIAlertController。我也试着提醒。dismissViewControllerAnimated(true, completion: nil)而不是self。dismissViewControllerAnimated(true, completion: nil),但是它也不会删除UIAlertController。

2 个解决方案

#1


1  

I wouldn't use a while loop but a didSet observer for your dataLoadingDone property. Thereby, you may try something similar to the following code:

我不会使用while循环,但会使用didSet观察者来查看您的dataLoadingDone属性。因此,您可以尝试以下代码:

class ViewController: UIViewController {

    var dismissAlertClosure: (() -> Void)?
    var dataLoadingDone = false {
        didSet {
            if dataLoadingDone == true {
                dismissAlertClosure?()
            }
        }
    }


    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)

        let alert = UIAlertController(title: "Please wait", message: "Retrieving data", preferredStyle: .Alert)
        presentViewController(alert, animated: true, completion: nil)

        // Set the dismiss closure to perform later with a reference to alert
        dismissAlertClosure = {
            alert.dismissViewControllerAnimated(true, completion: nil)
        }

        // Set boolValue to true in 5 seconds in order to simulate your asynchronous request completion
        var dispatchTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(5.0 * Double(NSEC_PER_SEC)))
        dispatch_after(dispatchTime, dispatch_get_main_queue(), { self.dataLoadingDone = true })
    }

}

#2


0  

Another user (matt) gave what I'm pretty sure is the correct answer, but he removed it, so I'm going to answer it. Just wanted to give credit (though he seems pretty reputable anyways).

另一个用户(马特)给出了我非常确定的正确答案,但他删除了,所以我将回答它。我只是想给他点功劳(尽管他看起来很有声望)。

What he wrote is that my UIAlertController presentation was not finished before I tried to dismiss it, so I got that error. I changed my code to the following:

他写的是,我的UIAlertController演示在我试图关闭它之前没有完成,所以我得到了这个错误。我将代码更改为以下内容:

// check if I need to wait at all
if (!dataLoadingDone) {
        var alert = UIAlertController(title: "Please wait", message: "Retrieving data", preferredStyle: UIAlertControllerStyle.Alert)

        self.presentViewController(alert, animated: true, completion: { () -> Void in
            // moved waiting and dismissal of UIAlertController to inside completion handler
            while (!self.dataLoadingDone) {

            }

            self.dismissViewControllerAnimated(true, completion: nil)
        })
    }

I moved the waiting and dismissal inside the completion handler of the presentViewController call, so that I know the presenting is done before dismissing. Also, I check if I need to wait at all with the first if statement, because otherwise another issue occurs if the while loop never does anything.

我在presentViewController调用的完成处理程序中移动了等待和解散,这样我就知道在解散之前要做演示了。另外,我检查是否需要等待第一个if语句,因为如果while循环不执行任何操作,则会出现另一个问题。

I'm not 100% sure yet, because my boolean is actually never false at the moment (the data retrieval happens really quickly). However, I have reason to believe it will take longer later on in my app development, so I will update the answer here once I have that.

我还不能百分之百确定,因为我的布尔值现在实际上从来都不是假的(数据检索发生得很快)。然而,我有理由相信,在我的应用开发中,这将花费更长的时间,所以一旦我有了答案,我将在这里更新答案。

EDIT: another user who previously posted an answer (Aaron Golden) was also correct about while loop blocking. I had thought that the while loop shares processing time with other events, but apparently not (or at least not enough time). Therefore, the above while loop DOES NOT work

编辑:之前发布答案的另一个用户(Aaron Golden)在循环阻塞时也是正确的。我曾认为while循环与其他事件共享处理时间,但显然没有(或者至少没有足够的时间)。因此,上面的while循环不起作用

#1


1  

I wouldn't use a while loop but a didSet observer for your dataLoadingDone property. Thereby, you may try something similar to the following code:

我不会使用while循环,但会使用didSet观察者来查看您的dataLoadingDone属性。因此,您可以尝试以下代码:

class ViewController: UIViewController {

    var dismissAlertClosure: (() -> Void)?
    var dataLoadingDone = false {
        didSet {
            if dataLoadingDone == true {
                dismissAlertClosure?()
            }
        }
    }


    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)

        let alert = UIAlertController(title: "Please wait", message: "Retrieving data", preferredStyle: .Alert)
        presentViewController(alert, animated: true, completion: nil)

        // Set the dismiss closure to perform later with a reference to alert
        dismissAlertClosure = {
            alert.dismissViewControllerAnimated(true, completion: nil)
        }

        // Set boolValue to true in 5 seconds in order to simulate your asynchronous request completion
        var dispatchTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(5.0 * Double(NSEC_PER_SEC)))
        dispatch_after(dispatchTime, dispatch_get_main_queue(), { self.dataLoadingDone = true })
    }

}

#2


0  

Another user (matt) gave what I'm pretty sure is the correct answer, but he removed it, so I'm going to answer it. Just wanted to give credit (though he seems pretty reputable anyways).

另一个用户(马特)给出了我非常确定的正确答案,但他删除了,所以我将回答它。我只是想给他点功劳(尽管他看起来很有声望)。

What he wrote is that my UIAlertController presentation was not finished before I tried to dismiss it, so I got that error. I changed my code to the following:

他写的是,我的UIAlertController演示在我试图关闭它之前没有完成,所以我得到了这个错误。我将代码更改为以下内容:

// check if I need to wait at all
if (!dataLoadingDone) {
        var alert = UIAlertController(title: "Please wait", message: "Retrieving data", preferredStyle: UIAlertControllerStyle.Alert)

        self.presentViewController(alert, animated: true, completion: { () -> Void in
            // moved waiting and dismissal of UIAlertController to inside completion handler
            while (!self.dataLoadingDone) {

            }

            self.dismissViewControllerAnimated(true, completion: nil)
        })
    }

I moved the waiting and dismissal inside the completion handler of the presentViewController call, so that I know the presenting is done before dismissing. Also, I check if I need to wait at all with the first if statement, because otherwise another issue occurs if the while loop never does anything.

我在presentViewController调用的完成处理程序中移动了等待和解散,这样我就知道在解散之前要做演示了。另外,我检查是否需要等待第一个if语句,因为如果while循环不执行任何操作,则会出现另一个问题。

I'm not 100% sure yet, because my boolean is actually never false at the moment (the data retrieval happens really quickly). However, I have reason to believe it will take longer later on in my app development, so I will update the answer here once I have that.

我还不能百分之百确定,因为我的布尔值现在实际上从来都不是假的(数据检索发生得很快)。然而,我有理由相信,在我的应用开发中,这将花费更长的时间,所以一旦我有了答案,我将在这里更新答案。

EDIT: another user who previously posted an answer (Aaron Golden) was also correct about while loop blocking. I had thought that the while loop shares processing time with other events, but apparently not (or at least not enough time). Therefore, the above while loop DOES NOT work

编辑:之前发布答案的另一个用户(Aaron Golden)在循环阻塞时也是正确的。我曾认为while循环与其他事件共享处理时间,但显然没有(或者至少没有足够的时间)。因此,上面的while循环不起作用