I am new to swift and I have a login page that takes the users credentials and check if it's the right credentials . I think return the response in JSON if it's the right credentials then I try to go to a new ViewController .I got this error when I try to go to a new View Controller, I have this in a closure so I do not know why I am getting this issue. This is my code
func LoginClosure(completion:@escaping (Bool) ->Void) {
var check = 0
let url:URL = URL(string:ConnectionString+"login")!
if submitEmail == nil || submitPassword == nil {
submitEmail = email.text!
submitPassword = password.text!
}
let session = URLSession.shared
var request = URLRequest(url: url)
request.httpMethod = "POST"
let parameter = "Email=\(submitEmail!)&password=\(submitPassword!)"
request.httpBody = parameter.data(using: String.Encoding.utf8)
DispatchQueue.main.async {
session.dataTask(with:request, completionHandler: { (data, response, error) in
if error != nil {
// print(error)
} else {
do {
let parsedData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:Any]
if let Streams = parsedData?["Profile"] as? [AnyObject] {
// check for misspelled words
for Stream in Streams {
if let rr = Stream["result"] as? Bool {
self.result = rr
} else {
self.result = true
}
if let id = Stream["id"] as? Int {
self.defaults.setValue(id, forKey: "my_id")
// Success
MYID = id
completion(true)
return
}
}
if check == 0 {
// Bad credentials
completion(false)
}
}
} catch let error as NSError {
print(error)
}
}
}).resume()
}
}
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Only run on the main thread!'
That error occurs with this line:
let next = self.storyboard?.instantiateViewController(withIdentifier: "AccountC") as! AccountC
self.present(next, animated: true, completion: nil)
As per apple standards, you have to perform UI activity in the main queue only.
Just call your closure in the main queue
as below.
DispatchQueue.main.async {
completion(true)
}
You can also perform only UI changes in the main queue
as below.
DispatchQueue.main.async {
let next = self.storyboard?.instantiateViewController(withIdentifier: "AccountC") as! AccountC
self.present(next, animated: true, completion: nil)
}
@rmaddy Thanks for the valuable suggestion.
In your code, I see that you have initiated the network call in the main queue. That makes sure that creation of the data task and starting it off will be performed on the main thread. But it doesn't guarantee that the completion closure will also be called on the main thread.
Therefore I would suggest removing the network call from the DispatchQueue.main.async
block. Then please execute the code that performs UI updation in a DispatchQueue.main.async block
as follows.
DispatchQueue.main.async {
let next = self.storyboard?.instantiateViewController(withIdentifier: "AccountC") as! AccountC
self.present(next, animated: true, completion: nil)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With