Blocking the main queue - swift

I want flag to change as 'false' but it stays 'true'. How can I block my main queue ? Could you please explain with code ?
var flag = true;
var url = NSURL(string: "http://www.google.com")
var task = NSURLSession.sharedSession().dataTaskWithURL(url!){
(data,response,error) in
var urlContent = NSString(data: data, encoding: NSUTF8StringEncoding)
flag = false
}
task.resume()
println(flag)

If you want to make a synchronous request, one that blocks the current thread, you should just use NSURLConnection's sendSynchronousRequest:returningResponse:error: instead. There is no reason to create a download task if you want to block until it is done.
let request = NSURLRequest(URL: url!)
var response: NSURLResponse?
var error: NSError?
if let data = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: &error) {
let urlContent = NSString(data: data, encoding: NSUTF8StringEncoding)
}
else {
// handle error
}
However, blocking the main thread waiting for a network request is a really bad idea. The user will certainly notice the freeze in the app and be frustrated. I would strongly advise you to find a way of achieving this without having to block the main thread.

Related

URLTask does not send any UrlRequest

I am new to swift and doing a project in swift 4.0 to acquire data form Fitbit API and got a Strange problem, my url task does not send any urlrequest any more but skip all the code until task.resume, and do not give anything back. Can anyone helps me plz. The code is shown below
import UIKit
class FitbitAPI{
static let sharedInstance : FitbitAPI = FitbitAPI()
var parsedJson : [Any]? = nil
func authorize(with token: String){
let accessToken = token
let baseURL = URL(string: "https://api.fitbit.com/1/user/-/activities/steps/date/today/1m.json")
let request = NSMutableURLRequest(url:baseURL!)
let bodydata = "access_token=\(String(describing: accessToken))"
request.httpMethod = "GET"
request.setValue("Bearer \(String(describing: accessToken))", forHTTPHeaderField: "Authorization")
request.httpBody = bodydata.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request as URLRequest, completionHandler: {[weak self] (data, response, error) in
if let error = error {
print(error)
}
if let data = data, error == nil{
do {
self?.parsedJson = (try JSONSerialization.jsonObject(with: data, options: []) as? [Any] )
print(String(describing: self?.parsedJson))
}catch _{
print("Received not-well-formatted JSON")
}
}
if let response = response {
let httpResponse = response as! HTTPURLResponse
print("response code = \(httpResponse.statusCode)")
}
})
task.resume()
}
}
As #Larme implied in his comment, all of that code between the let task = line and the task.resume() line is a callback. Meaning it won't get called until the task completes. Put breakpoints inside of that callback (like on your if let error = error line), and see if they get hit.
ALso, your URL task is a local variable in this method. That means it's entirely possible that its getting released from memory right at the end of this method, before the callback can even be executed. You'll need a reference to the task outside of the method if you want to guarantee that it stays alive in memory long enough to hit the completion callback.

How can we wait for HTTP requests to finish?

Using several answers on SO, we have managed to write and execute a basic HTTP request:
import Foundation
let url:URL = URL(string: "http://jsonplaceholder.typicode.com/posts")!
let session = URLSession.shared
var request = URLRequest(url: url)
request.httpMethod = "POST"
let paramString = "data=Hello"
request.httpBody = paramString.data(using: String.Encoding.utf8)
let task = session.dataTask(with: request as URLRequest) {
(data, response, error) in
guard let data = data, let _:URLResponse = response, error == nil else {
print("error")
return
}
let dataString: String = String(data: data, encoding: String.Encoding.utf8)!
print("here")
print("Data: \(dataString)")
print("Response: \(response!)")
}
task.resume()
while task.response == nil {}
print("Done")
You'll note that we already busy-wait until task.response is set. However, neither data nor response are printed, only here.
After endless trials with wrapping things this or that way we determine that we have a Heisenbug here: changing nothing in the code, sometimes here is printed, sometimes nothing, and very, very rarely dataString (let alone response).
So we insert sleep(3) before print("Done") and, wonder of wonders, we get all prints.
Then we yelled a little bit (I may actually have thrown something), thought briefly about abandoning Swift altogether, but then calmed down enough to facepalm like sirs and post here.
Apparently, the main thread terminates whether or not any asynchronous tasks (threads?) are still running or not, killing all its spawn. How can we prevent that from happening, that is "join" the threads?
Bonus question: Does Alamofire deal with this behind the covers?
Using CwUtils by Matt Gallagher, I implemented a simple CountdownLatch which does the job:
import Foundation
import CwlUtils
<...>
let task = session.dataTask(with: request as URLRequest) {
(data, response, error) in
<...>
latch.countDown()
}
task.resume()
latch.await()
The most straight-forward (and built-in) way is probably to use a DispatchSemaphore:
<...>
let sem = DispatchSemaphore(value: 0)
let task = session.dataTask(with: request as URLRequest) {
(data, response, error) in
<...>
sem.signal()
}
task.resume()
sem.wait()
Active waiting seems to be the only way on the GCD. Using standard library material, this is what works:
import Foundation
<...>
var done = false
let task = session.dataTask(with: request as URLRequest) {
(data, response, error) in
<...>
done = true
}
task.resume()
repeat {
RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.1))
} while !done

Completion handler for Post to server

I found this awesome answer to posting data to php
The only problem is, I don't know how to return the data upon completion.
How can I make a completion handler for the following function?
func postToServer(postURL: String, postString: String) {
let request = NSMutableURLRequest(URL: NSURL(string: postURL)!)
request.HTTPMethod = "POST"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request){
data, response, error in
let responseString = String(data: data!, encoding: NSUTF8StringEncoding)
if responseString != nil {
print("responseString = \(responseString!)")
}
}
task.resume()
}
Edit: Maybe I didn't apply it correctly, but the suggested duplicate link did not solve my problem. Could somebody please provide an example of this? I've been stuck on this for like 3 weeks now. I just don't know how to pull the data from task when it's completed. I've been reading up a lot on closures, but I just don't see where or even how these are related. When I try to find functions related to task, it only gives response...and that returns nil if I don't type in sleep(3) after resume.
I've watched a bunch of videos where people have the same code as me and don't use a completion handler and still get data back... what gives?
This works in swift 3
func postToServer(_ completion:#escaping (( _ response: String, _ success: Bool )-> Void), postURL: String, postString: String) {
let request = NSMutableURLRequest(url: NSURL(string: postURL)! as URL)
request.httpMethod = "POST"
request.httpBody = postString.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request as URLRequest){
data, response, error in
let responseString = String(data: data!, encoding: String.Encoding.utf8)
if responseString != nil {
print("responseString = \(responseString!)")
completion(responseString!, true)
}
}
task.resume()
}
}

A few questions on NSURLSession (request data) in Swift 2

I have been following this tutorial to learn Swift and I have a few questions on the way they do things.
Specifically here:
let paramString = "data=Hello"
request.HTTPBody = paramString.dataUsingEncoding(NSUTF8StringEncoding)
let task = session.dataTaskWithRequest(request) {
(data, response, error) in
guard let _:NSData = data, let _:NSURLResponse = response where error == nil else {
print("Error")
return
}
let dataString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print(dataString)
}
Why is (data, response, error) in always used in NSURLSessions? What does this line of code mean? Also, why does he have a guard statement underneath?
The whole section of code is here:
func dataRequest() {
let urlToRequest: String = " http://www.kaleidosblog.com/tutorial/nsurlsession_tutorial.php"
let url: NSURL = NSURL(string: urlToRequest)!
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringCacheData
let paramString = "data=Hello"
request.HTTPBody = paramString.dataUsingEncoding(NSUTF8StringEncoding)
let task = session.dataTaskWithRequest(request) {
(data, response, error) in
guard let _:NSData = data, let _:NSURLResponse = response where error == nil else {
print("Error")
return
}
let dataString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print(dataString)
}
task.resume()
}
With NSURLSession you make asynchronous calls, meaning that you make / start a network request and your program continues running - it doesn't stop waiting for response. Then, when your response is ready a completion block gets called / executed. So you need a way to access the data that's coming to you with this response. This data is accessible to you with (data, response, error) properties. This are just the names of those properties, so that you know how to use them. You could have different names, but it would be confusing to anyone else.
You use the guard statement because you can't be sure that you actually have the data or the response. It could be nil if an error occurred (timeout, ...). In such case (if there's an error) you just print "Error" to the console and call return, which makes you leave the completion block without executing the lines let dataString = NSString(data: data!, encoding: NSUTF8StringEncoding) and print(dataString). Of course, if you have the data and the response and error == nil you skip the else block of the guard statement and you just execute you last two lines of code in the block.

swift is slow at updating view after a REST POST request

I'm sending some POST request to my sever with swift, the usual:
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
println("error=\(error)")
return
}
let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
println(responseString) //this is fast
label.text = "\(responseString)" // this is very slow
}
task.resume()
This works well, I get the data and all. Now there are 2 things that behave very differently and I can't figure out why.
The line: println(responseString) print the data instantly as expected, however, the line label.text = "\(responseString)" takes about 10 seconds to update the label's text.
Any ideas why? has DrawRect got anything to do with this?
Try doing it on the main thread like this:
dispatch_async(dispatch_get_main_queue(), { () -> Void in
label.text = "\(responseString)"
})