Reputation: 77
I need to login through api when user click login button. The return results might failure or success. I want to use alterview to notice the user.
I defined one global variable in class:
var responseString:String = "";
In button click event:
@IBAction func login(sender: AnyObject) {
sendPostLoginRequest {
results in
println("here:\(results)")
self.responseString = results
}
var myAlert = UIAlertController(title:"Alert", message:self.responseString, preferredStyle: UIAlertControllerStyle.Alert);
let okAction = UIAlertAction(title:"Ok", style:UIAlertActionStyle.Default, handler:nil);
myAlert.addAction(okAction);
self.presentViewController(myAlert, animated:true, completion:nil);
}
The self.responseString is empty, even through i can get it in sendPostLoginRequest function:
func sendPostLoginRequest(completionHandler:(result:String)->()){
let name = usernamefield.text
let password = passwordfield.text
let request = NSMutableURLRequest(URL: NSURL(string: "http://www.xxx.xxx/api/user/login")!)
request.HTTPMethod = "POST"
let postString = "username=\(name)&password=\(password)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
}
let json = JSON(data: data)
println("results: \(json) ")
self.responseString = json[0].string!
//json[0].string! can be success or failure
completionHandler(result:self.responseString)
}
task.resume()
}
Upvotes: 0
Views: 2862
Reputation: 1585
The way I see it, I think when you click the button, the alertView is shown without the responseString or nil. The problem is you are anticipating the block will get called later on and hence the data for responseString will be set later in time but the code below will continue to execute.
The long way to do is:
//observe this variable and when something changes we will alert it
var responseString:String {
didSet{
//do some checking or other work
presentAlert(responseString)
}
}
@IBAction func login(sender: AnyObject) {
sendPostLoginRequest {
results in
println("here:\(results)")
self.responseString = results
}
}
func presentAlert(msg:String){
var myAlert = UIAlertController(title:"Alert", message:msg, preferredStyle: UIAlertControllerStyle.Alert);
let okAction = UIAlertAction(title:"Ok", style:UIAlertActionStyle.Default, handler:nil);
myAlert.addAction(okAction);
self.presentViewController(myAlert, animated:true, completion:nil);
}
The short way to do is:
@IBAction func login(sender: AnyObject) {
sendPostLoginRequest {
results in
println("here:\(results)")
self.responseString = results
dispatch_async(dispatch_get_main_queue(), { () -> Void in
//update ui from main thread always
self.presentAlert(results) //may pass responseString too
})
}
}
func presentAlert(msg:String){
var myAlert = UIAlertController(title:"Alert", message:msg, preferredStyle: UIAlertControllerStyle.Alert);
let okAction = UIAlertAction(title:"Ok", style:UIAlertActionStyle.Default, handler:nil);
myAlert.addAction(okAction);
self.presentViewController(myAlert, animated:true, completion:nil);
}
Had you put the code below the closure inside it would have worked but you would be running UI things from other threads which are bad so use Dispatch Async to work for long-running operations on a separate thread.
Let me know if that helps and hope it does. Cheers!
Upvotes: 1