【问题标题】:When and where to dismiss UIAlertController in Swift?何时何地在 Swift 中关闭 UIAlertController?
【发布时间】:2023-03-29 21:18:01
【问题描述】:

我正在调用一个执行 URLSession 的方法,但在它执行任何操作之前,会呈现一个 UIAlertController 阻塞 UI,直到获得来自请求的某种响应。逻辑告诉我,在主线程上调用该方法的完成块中取消 UIAlertController 将是最佳选择。我认为这是错误的吗?显然如此,所呈现的UIAlertController 确实会显示,但永远不会关闭。帮忙?

块:

getCostandIV { output in

            let cost = output["ask"] as! NSNumber
            let IV = output["IV"] as! NSNumber

            self.enteredCost = cost.stringValue
            self.enteredIV = IV.stringValue

            DispatchQueue.main.async {

                self.progress.dismiss(animated: true, completion: nil)
                self.tableView.reloadSections(IndexSet(integer: 1), with: UITableView.RowAnimation.none)
                self.canWeSave()

            }

        }

功能:

 func getCostandIV (completionBlock: @escaping (NSMutableDictionary) -> Void) -> Void {

    DispatchQueue.main.async {


        self.progress = UIAlertController(title: "Retrieving ask price and volatility...", message: nil, preferredStyle: UIAlertController.Style.alert)
        self.present(self.progress, animated: true, completion: nil)

    }

    guard let url = URL(string: "https://api.tdameritrade.com/v1/marketdata/chains?apikey=test&symbol=\(symbol)&contractType=\(type)&strike=\(selectedStrike)&fromDate=\(selectedExpiry)&toDate=\(selectedExpiry)") else {
        return
    }

    let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
        guard let dataResponse = data,
            error == nil else {
                //print(error?.localizedDescription ?? "Response Error")

                DispatchQueue.main.async {


                        self.presentedViewController?.dismiss(animated: true, completion: {

                        let alert = UIAlertController(title: "There was an error retrieving ask price and volatility.", message: "Please try again later.", preferredStyle: .alert)
                        alert.addAction(UIAlertAction(title: "OK", style: .default))
                        self.present(alert, animated: true)

                    })

                }

                return }
        do{
            //here dataResponse received from a network request
            let jsonResponse = try JSONSerialization.jsonObject(with:
                dataResponse, options: [])
            //                //print(jsonResponse) //Response result

            guard let jsonDict = jsonResponse as? NSDictionary else {
                return
            }
            //                //print(jsonDict)

            var strikeMap : NSDictionary = [:]

            if self.type == "CALL" {
                strikeMap = jsonDict["callExpDateMap"] as! NSDictionary

            } else {
                strikeMap = jsonDict["putExpDateMap"] as! NSDictionary

            }

            self.strikes.removeAllObjects()

            let inner = strikeMap.object(forKey: strikeMap.allKeys.first ?? "<#default value#>") as! NSDictionary
            let innerAgain = inner.object(forKey: inner.allKeys.first ?? "<#default value#>") as! NSArray
            let dict : NSDictionary = innerAgain[0] as! NSDictionary

            let dict2 = ["ask" : dict["ask"] as! NSNumber, "IV" : dict["volatility"] as! NSNumber] as NSMutableDictionary



            completionBlock(dict2)


        } catch let parsingError {
            print("Error", parsingError)
        }
    }
    task.resume()
}

编辑:使用self.presentedViewController?.dismiss(animated: true, completion: nil) 并不能解决问题。另外,self.progress的dismiss函数的完成块也没有被调用。

编辑 2: 回调中的关闭代码之前的presentViewController 为nil,即使在关闭之前在警报控制器上调用了present?

【问题讨论】:

    标签: ios swift uialertcontroller


    【解决方案1】:

    使用这个,为了解除你的警报,你应该在异步块中添加解除方法,并为此设置计时器,你应该告诉异步块从现在到 5 秒开始异步,然后做一些事情:

            alert.addAction(UIAlertAction(title: "ok", style: .default,
                                          handler: nil))
            viewController.present(alert, animated: true, completion: nil)
    
            // change to desired number of seconds (in this case 5 seconds)
            let when = DispatchTime.now() + 5
            DispatchQueue.main.asyncAfter(deadline: when){
                // your code with delay
                alert.dismiss(animated: true, completion: nil)
            }
    

    【讨论】:

    • 因为它在你想要的时间后自动关闭,如果你不需要,你可以删除这部分。
    【解决方案2】:

    如果你多次调用getCostandIV方法,第二个alert就不会出现,self.progress会有unpresented alert的引用。

    改变

    self.progress.dismiss(animated: true, completion: nil)
    

    到

    self.presentedViewController?.dismiss(animated: true, completion: nil)
    

    【讨论】:

    • 刚试过这个,以为它可以工作一秒钟,但第一次调用 getCostandIV 时,它永远不会关闭。有没有更好的方法让我处理呈现警报?
    • @ahjnar 在这一行使用断点,检查是否调用了补全
    • 我现在正在测试的一些可能有用的信息:使用计时器延迟解除警报现在显示出工作迹象..
    • @ahjnar 显示getCostandIV方法的完整代码。
    • 只是这样做了,如果我跳过断点(调用完成),警报会正确解除。只是不是靠自己..
    【解决方案3】:

    只有在一切顺利的情况下,您的警报才会被解除。 我建议你把你的功能改成这样:

     func getCostandIV (completionBlock: @escaping (NSMutableDictionary?, Error?) -> Void) -> Void
    

    并确保在您的guard 语句失败或抛出错误时调用您的completionBlock。在您当前的代码中,警报仅在网络请求失败时才解除,但在解析 JSON 时出现问题时不会解除。

    【讨论】:

    • 不是这个问题的答案,而是为乐于助人而投票!我会考虑添加这个。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2015-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多