Reputation: 96
From everything I read you can activate it with with a button so I put it right after the button action that starts the http POST and upload, but right now it starts spinning right after the function has finished, after the upload is complete, the opposite of what I would expect.
I'm new to Swift so please explain your answer as you would to a nubie. Many thanks.
@IBAction func upload(sender: AnyObject) {
myActivityIndicator.startAnimating()
var imageData = UIImagePNGRepresentation(myImageView.image)
if imageData != nil{
var request = NSMutableURLRequest(URL: NSURL(string:"http://www.example.com/upload.php")!)
var session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
var boundary = NSString(format: "---------------------------14737809831466499882746641449")
var contentType = NSString(format: "multipart/form-data; boundary=%@",boundary)
// println("Content Type \(contentType)")
request.addValue(contentType, forHTTPHeaderField: "Content-Type")
var body = NSMutableData.alloc()
// Title
body.appendData(NSString(format: "\r\n--%@\r\n",boundary).dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData(NSString(format:"Content-Disposition: form-data; name=\"title\"\r\n\r\n").dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData("Hello World".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!)
// Image
body.appendData(NSString(format: "\r\n--%@\r\n", boundary).dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData(NSString(format:"Content-Disposition: form-data; name=\"profile_img\"; filename=\"img.jpg\"\r\n").dataUsingEncoding(NSUTF8StringEncoding)!)
// println("body=\(body)")
body.appendData(NSString(format: "Content-Type: application/octet-stream\r\n\r\n").dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData(imageData)
body.appendData(NSString(format: "\r\n--%@\r\n", boundary).dataUsingEncoding(NSUTF8StringEncoding)!)
request.HTTPBody = body
var returnData = NSURLConnection.sendSynchronousRequest(request, returningResponse: nil, error: nil)
var returnString = NSString(data: returnData!, encoding: NSUTF8StringEncoding)
println("returnString \(returnString)")
//self.myActivityIndicator.stopAnimating()
//self.myImageView.image = nil
}
}
Upvotes: 3
Views: 588
Reputation: 22926
This is occurring because this call is blocking the main thread (which is responsible for updating the UI:
var returnData = NSURLConnection.sendSynchronousRequest(request, returningResponse: nil, error: nil)
Thus, after this line of code everything you do on the UI will not show up until after this synchronous call has completed.
The solution here is to make this call on a background thread, and then when finished update the UI on the main thread.
One of the nicest ways to achieve this is using GCD (Grand Central Dispatch). GCD is a thread API which makes doing work on a background thread easy peasy.
As already mentioned in the answer above:
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), {
var returnData = NSURLConnection.sendSynchronousRequest(request, returningResponse: nil, error: nil)
dispatch_async(dispatch_get_main_queue()) {
myActivityIndicator.stopAnimating()
}
})
One of the key tenets in iOS development is not blocking the main thread.
This leads to a bad user experience.
Furthermore, it's really important to always update the UI on the main thread.
Just so you know there are other ways to handle this kind of situation without GCD (threading API), NSOperation
for example.
Also, you could send an asynchronous request instead.
Upvotes: 1
Reputation: 104
try this
myActivityIndicator.startAnimating()
dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_USER_INITIATED.value), 0)) {
//Do your post code here or call the post func
dispatch_async(dispatch_get_main_queue()) {
myActivityIndicator.stopAnimating()
}
}
http://ijoshsmith.com/2014/07/29/a-swift-app-that-calls-json-web-services/ http://www.raywenderlich.com/79149/grand-central-dispatch-tutorial-swift-part-1
Upvotes: 1