在 Swift 中何时何地关闭 UIAlertController?
When and where to dismiss UIAlertController in Swift?
我正在调用一个执行 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 的关闭函数的完成块。
编辑 2:presentedViewController 就在关闭之前,回调中的代码为 nil,即使在关闭之前在警报控制器上调用了 present?
如果您多次调用 getCostandIV
方法,则不会显示第二个警报,并且 self.progress
将引用未显示的警报。
改变
self.progress.dismiss(animated: true, completion: nil)
到
self.presentedViewController?.dismiss(animated: true, completion: nil)
使用这个,为了关闭你的警报,你应该在异步块中添加关闭方法,并为此设置定时器,你应该告诉异步块从现在到 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)
}
只有在一切顺利的情况下,您的提醒才会被解除。
我建议你把你的功能改成这样:
func getCostandIV (completionBlock: @escaping (NSMutableDictionary?, Error?) -> Void) -> Void
并确保在 guard
语句失败或抛出错误时调用 completionBlock
。在您当前的代码中,仅当网络请求失败时才会解除警报,但不会在解析 JSON.
时出现问题
我正在调用一个执行 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 的关闭函数的完成块。
编辑 2:presentedViewController 就在关闭之前,回调中的代码为 nil,即使在关闭之前在警报控制器上调用了 present?
如果您多次调用 getCostandIV
方法,则不会显示第二个警报,并且 self.progress
将引用未显示的警报。
改变
self.progress.dismiss(animated: true, completion: nil)
到
self.presentedViewController?.dismiss(animated: true, completion: nil)
使用这个,为了关闭你的警报,你应该在异步块中添加关闭方法,并为此设置定时器,你应该告诉异步块从现在到 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)
}
只有在一切顺利的情况下,您的提醒才会被解除。 我建议你把你的功能改成这样:
func getCostandIV (completionBlock: @escaping (NSMutableDictionary?, Error?) -> Void) -> Void
并确保在 guard
语句失败或抛出错误时调用 completionBlock
。在您当前的代码中,仅当网络请求失败时才会解除警报,但不会在解析 JSON.