问题
I have created an overlay to run while I run an async data grab to the server so that users won't continue pressing buttons in the UI until the data grab is done. I have put the function into a global singleton class and I call it while passing in a bool to say whether or not I want to show or hide. I can get it to show but I cannot get it to hide. Here is the code:
class DataModel {
static let sharedInstance = DataModel()
func accessNetworkData(vc: UIViewController, params: [String:Any], wsURLPath: String, completion: @escaping (_ response: AnyObject) -> ()) {
DataModel.sharedInstance.toggleModalProgess(show: true)
// SHOW THE MODAL HERE ONCE THE DATA IS REQUESTED.
let url = URL(string: wsURLPath)!
let session = URLSession.shared
var request = URLRequest(url: url)
request.httpMethod = "POST"
do { request.httpBody = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted) } catch let error { print(error.localizedDescription) }
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
DataModel.sharedInstance.toggleModalProgess(show: false)
// NOW SINCE THE NETWORK ACTIVITY IS DONE, HIDE THE UIALERTCONTROLLER
guard error == nil else {
print("WEB SERVICE ERROR <----------------------------<<<<<< " + wsURLPath)
print(error!)
let resp: [String: String] = [ "conn": "failed" ]
DispatchQueue.main.async { completion(resp as NSDictionary) }
return
}
guard let data = data else {
print("WEB SERVICE ERROR <----------------------------<<<<<< " + wsURLPath)
return
}
do {
if let parsedJSON = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
print("WEB SERVICE SUCCESS <----------------------------<<<<<< "+wsURLPath+" "+String(describing:params))
if let parsedResponseDict = parsedJSON["d"] as? NSDictionary {
DispatchQueue.main.async {
completion(parsedResponseDict)
}
}else if let parsedResponseArr = parsedJSON["d"] as? NSArray {
DispatchQueue.main.async {
completion(parsedResponseArr)
}
}else {
print("INVALID KEY <----------------------------<<<<<< " + wsURLPath)
DispatchQueue.main.async {
completion(parsedJSON as AnyObject)
}
}
}
} catch let error {
print("Error with JSON Serialization")
print(error.localizedDescription)
}
})
task.resume()
}
HERE IS WHERE I SET UP THE UIALERTCONTROLLER
let modalAlert = UIAlertController(title: "Please Wait...", message: "Loading Data...", preferredStyle: UIAlertControllerStyle.alert)
let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50))
func toggleModalProgess(show: Bool) -> Void {
print("toggleModalProgess: show = " + String(describing: show))
if (show) {
print("let's turn it on")
loadingIndicator.hidesWhenStopped = true
loadingIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.gray
loadingIndicator.startAnimating()
modalAlert.view.addSubview(loadingIndicator)
modalAlert.show()
}else {
print("let's turn it off")
modalAlert.hide()
}
}
private init() { }
}
NOW THE EXTENSION WHERE THE MAGIC HAPPENS
public extension UIAlertController {
func show() {
let win = UIWindow(frame: UIScreen.main.bounds)
let vc = UIViewController()
vc.view.backgroundColor = .clear
win.rootViewController = vc
win.windowLevel = UIWindowLevelAlert + 1
win.makeKeyAndVisible()
vc.present(self, animated: true, completion: nil)
}
func hide() {
// HERE IS WHERE I NEED TO HIDE IT BUT I AM HAVING ISSUES
}
}
回答1:
In order to dismiss the UIAlertController
(which is a subclass of UIViewController
), it should be sufficient to call the dismiss
method:
func hide() {
dismiss(animated: true, completion: nil)
}
It works fine in my sample project.
回答2:
You should do...
self.presentingViewController?.dismiss(animated: true, completion: nil)
Hope it helps
来源:https://stackoverflow.com/questions/44728819/ios-10-swift-3-cannot-dismiss-uialertcontroller-from-singleton-instance