URLTask does not send any UrlRequest - swift

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.

Related

Returning data from URLSession in Swift

I have tried to research this issue and am unable to find a suitable fix. I attached an image of the code. I am trying to return the subscriptions array which is declared before the URLSession, and data is appended during the URLSession. However, it returns the originally declared, empty array. I added print statements so you can understand what I am talking about. It prints 2 before 1.
let request = NSMutableURLRequest(url: NSURL(string: "https://utelly-tv-shows-and-movies-availability-v1.p.rapidapi.com/lookup?term=\(searchShow)&country=us")! as URL, cachePolicy: .useProtocolCachePolicy,timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
//let json = try? JSONSerialization.jsonObject(with: data!, options: [])
//print(json)
} else {
//let httpResponse = response as? HTTPURLResponse
let decoder = JSONDecoder()
let json = try! decoder.decode(results.self, from: data!)
//print(json) (for debugging use only)
//print(httpResponse)
for item in json.results{
for each in item.locations{
subscriptions.append(each.display_name)
}
}
//Remove duplicates from array
let uniqueUnordered = Array(Set(subscriptions))
let uniqueOrdered = Array(NSOrderedSet(array: uniqueUnordered))
subscriptions = uniqueOrdered as! [String]
//Print subscriptions array
print("1: \(subscriptions)")
}
})
dataTask.resume()
print("2: \(subscriptions)")
return subscriptions

How can I parse JSON from a rest API in swift

I'm modifying code from 'Hacking with swift' Project 7 to take a JSON file using an API and placing it in a table view
I'm at a bit of loss of what to do next, tried moving around the call to the parse function and using the commented out code
override func viewDidLoad() {
super.viewDidLoad()
let username = "UserName"
let password = "Password"
let loginData = String(format: "%#:%#", username,
password).data(using: String.Encoding.utf8)!
let base64LoginData = loginData.base64EncodedString()
let url = URL(string: "......")!
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("Basic \(base64LoginData)", forHTTPHeaderField:
"Authorization")
let task = URLSession.shared.dataTask(with: request) { data,
response,
error in
guard let data = data, error == nil else {
print("error")
return
}
if let httpStatus = response as? HTTPURLResponse {
parse(json: data)
print("status code = \(httpStatus.statusCode)")
}
}
task.resume()
}
// if let url = URL(string: urlstring){
// if let data = try? Data(contentsOf: url){
// parse(json: data)
// return
// }
// }
// showError()
//}
func parse(json: Data) {
let decoder = JSONDecoder()
if let jsonPetitions = try? decoder.decode(Petitions.self, from:
json) {
petitions = jsonPetitions.results
tableView.reloadData()
}
}
I receive a status code of '200' so I know the API call works fine.
The issue seems to be with calling the parse function I get the
following error "Call to method 'parse' in closure requires explicit
'self.' to make capture semantics explicit"
1- The error means to add self here
self.parse(json: data)
2- You should reload the table in main thread as callback of URLSession.shared.dataTask runs in a background thread to avoid un-expected results/crashes
DispatchQueue.main.async {
self.tableView.reloadData()
}

Use Swift URLSession example code on command line tool

I am trying to figure out the simplest way to make an HTTP request in Swift 4 from the command line. I have copied this code from the URLSession programming guide, and added a couple print statements. I can't figure out why the .dataTask is not executing.
print("Testing URLSession")
let sessionWithoutADelegate = URLSession(configuration: URLSessionConfiguration.default)
if let url = URL(string: "https://www.example.com/") {
print("Encoded url \(url)")
(sessionWithoutADelegate.dataTask(with: url) { (data, response, error) in
print("Executing dataTask")
if let error = error {
print("Error: \(error)")
} else if let response = response,
let data = data,
let string = String(data: data, encoding: .utf8) {
print("Response: \(response)")
print("DATA:\n\(string)\nEND DATA\n")
}
}).resume()
}
The objective is to retrieve data from a REST api, but I can't even make a simple GET request to work properly...
I finally figured out how to make it work using CFRunLoop:
let runLoop = CFRunLoopGetCurrent()
let task = session.dataTask(with: request) { (data, response, error) in
print("Retrieved data")
CFRunLoopStop(runLoop)
}
task.resume()
CFRunLoopRun()
print("done")

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.

Making an API call in Swift 2.0

I've been scouring examples looking to pull some ideas together, I've come up with this although I'm not getting any output. It never enters the do which leads me to believe I have an issue with my call.
Can anyone shed some light on this for me or lead me to an appropriate location with more information on API calls in swift 2.0? Examples of this are quite sparse.
let url : String = "http://www.fantasyfootballnerd.com/service/nfl-teams/json/test/"
let request : NSMutableURLRequest = NSMutableURLRequest()
request.URL = NSURL(string: url)
request.HTTPMethod = "GET"
print("Start")
let session = NSURLSession.sharedSession()
session.dataTaskWithRequest(request) { (data, response, error) -> Void in
do {
let jsonResult: NSDictionary! = try NSJSONSerialization.JSONObjectWithData(data!, options:NSJSONReadingOptions.MutableContainers) as? NSDictionary
print("In method")
if (jsonResult != nil) {
// process jsonResult
print("Data added")
} else {
print("No Data")
// couldn't load JSON, look at error
}
}
catch {
print("Error Occured")
}
}
You're missing just one thing. You need to start the request:
// call this after you configure your session
session.dataTaskWithRequest(request) { (data, response, error) -> Void in
// process results
}.resume()