NSURLSession Show Tasks In Suspended State? - ios

I know that invoking getTasksWithCompletionHandler on an NSURLSession:
Asynchronously calls a completion callback with all outstanding data,
upload, and download tasks in a session.
However, from experimentation, I can see the data, upload, and download task arrays returned by the method;
func getTasksWithCompletionHandler(_ completionHandler: ([NSURLSessionDataTask], [NSURLSessionUploadTask], [NSURLSessionDownloadTask]) -> Void)
are in fact only show executing tasks. I.e., tasks which have received resume().
This can be seen by copy pasting this code in a Playground:
import UIKit
import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let url = NSURL(string: "http://jsonplaceholder.typicode.com")
let request: NSURLRequest = NSURLRequest(URL: url!)
let task : NSURLSessionDataTask = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
NSLog("Done")
})
session.getAllTasksWithCompletionHandler { (tasks:[NSURLSessionTask]) -> Void in
NSLog("\(tasks)")
XCPlaygroundPage.currentPage.finishExecution()
}
//task.resume()
Note that getTasksWithCompletionHandler and getAllTasksWithCompletionHandler - the latter released in iOS 9 - seem to only differ in the signature of the completion closure.
Also, somewhat tantalisingly, NSURLSessionTask has a state property NSURLSessionTaskState that gives us Running, Suspended, Canceling, Completed.
Is there a way to access the list of non-executing tasks; those that have been aded to the NSURLSession yet have not resumed?

Related

What is the better way to call multiple services in iOS?

I have 5 different services requests to load into same UItableView for each cells.
What is the best way to approach in order to do this.
https://example.com/?api/service1
https://example.com/?api/service2
https://example.com/?api/service3
https://example.com/?api/service4
https://example.com/?api/service5
let url = "https://example.com/?api/service1
Alamofire.request(url, method: .get, parameters:nil encoding: JSONEncoding.default, headers: nil)
.responseJSON { response in
print(response.result.value as Any) // result of response serialization
}
repeat the same Alamofire five times with different services name there is another way to implement it.
Look at using a DispatchGroup to perform multiple async requests and wait for them all to complete.
For each task you call group.enter() and in its completion handler when you know that request has finished you call group.leave(). Then there is a notify method which will wait for all requests to call leave to tell you that they have all finished.
I have created an example in a Playground (which will fail with errors because of the URL's used)
import UIKit
import PlaygroundSupport
let serviceLinks = [
"https://example.com/?api/service1",
"https://example.com/?api/service2",
"https://example.com/?api/service3",
"https://example.com/?api/service4",
"https://example.com/?api/service5"
]
// utility as I've not got alamofire setup
func get(to urlString: String, completion: #escaping (Data?, URLResponse?, Error?) -> Void) {
let url = URL(string: urlString)!
let session = URLSession.shared
let task = session.dataTask(with: url) { data, response, error in
completion(data, response, error)
}
task.resume()
}
let group = DispatchGroup()
for link in serviceLinks {
group.enter() // add an item to the list
get(to: link) { data, response, error in
// handle the response, process data, assign to property
print(data, response, error)
group.leave() // tell the group your finished with this one
}
}
group.notify(queue: .main) {
//all requests are done, data should be set
print("all done")
}
PlaygroundPage.current.needsIndefiniteExecution = true
You probably won't be able to just loop through the URL's like I have though because the handling of each service is probably different. You'll need to tweak it based on your needs.
There is alot more information about DispatchGroups available online such as this article

swift 3+, URLsession, in the background fails apparently at random

I am fairly new to swift(1 week) and iOS programming, and my problem is that I seem to miss some basic understanding. Below you see a function that is triggered by a background notification. I can and have verified that I receive the background notification reliably and the app comes active (printout of the raw data values on the console) As long as the app is in the foreground everything is working just as expected, it gets fired, and sends a single https request. The background triggers come on a timer every minute.
Now the whole thing changes when the app enters into the background. In this case I am still getting the triggers through the notification (console printout) and I can see in the debugger the same function that works like a charm in the foreground stumbles. It still works, it still gets fired, but a data packet is sent only so often, randomly as it seems between 2 and 30 minutes.
let config = URLSessionConfiguration.background(withIdentifier: "org.x.Reporter")
class queryService {
let defaultSession = URLSession(configuration: config)
var dataTask: URLSessionDataTask?
var errorMessage = ""
func getSearchResults(baseURL: String, searchTerm: String) {
dataTask?.cancel()
config.requestCachePolicy = .reloadIgnoringLocalAndRemoteCacheData;
config.timeoutIntervalForRequest = 10
if var urlComponents = URLComponents(string: "https://host.com/reportPosition.php") {
urlComponents.query = "\(searchTerm)"
guard let url = urlComponents.url else { return }
dataTask = defaultSession.dataTask(with: url)
}
// 7
dataTask?.resume()
}
}
Try using dataTaskWithCompletion so you can see what's going wrong in the error.
URLSession.shared.dataTask(with: URL.init(string: "")!) { (data, response, error) in
if error != nil {
// Error
}
}.resume()
https://developer.apple.com/documentation/foundation/urlsession/1410330-datatask
EDIT
What you want to do is for background you get completions via delegate call backs so when you init ur URLSession do so using the following func
URLSession.init(configuration: URLSessionConfiguration.init(), delegate: self, delegateQueue: OperationQueue.init())
https://developer.apple.com/documentation/foundation/urlsession/1411597-init
Then conform ur class to the URLSessionDelegate like so
class queryService, URLSessionDelegate {
then implement the delegate methods listed here for call backs
https://developer.apple.com/documentation/foundation/urlsessiondelegate
EDIT2
Here is good tutorial about it
https://www.raywenderlich.com/158106/urlsession-tutorial-getting-started

Downloading files in iOS [duplicate]

This question already has answers here:
How to download file in swift?
(16 answers)
Closed 6 years ago.
I'm trying to download a file using Swift. This is the downloader class in my code:
class Downloader {
class func load(URL: URL) {
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig, delegate: nil, delegateQueue: nil)
let request = NSMutableURLRequest(url: URL)
request.httpMethod = "GET"
let task = session.dataTask(with: URL)
task.resume()
}
}
I call the function like this:
if let URL = URL(string: "https://web4host.net/5MB.zip") {
Downloader.load(URL: URL)
}
but this error message pops up:
2017-02-16 04:27:37.154780 WiFi Testing[78708:7989639] [] __nw_connection_get_connected_socket_block_invoke 2 Connection has no connected handler
2017-02-16 04:27:37.167092 WiFi Testing[78708:7989639] [] __nw_connection_get_connected_socket_block_invoke 3 Connection has no connected handler
2017-02-16 04:27:37.169050 WiFi Testing[78708:7989627] PAC stream failed with
2017-02-16 04:27:37.170688 WiFi Testing[78708:7989639] [] nw_proxy_resolver_create_parsed_array PAC evaluation error: kCFErrorDomainCFNetwork: 2
Could someone tell me what I'm doing wrong and how I could fix it? Thanks!
The code to receive the data is missing.
Either use delegate methods of URLSession or implement the dataTask method with the completion handler.
Further for a GET request you don't need an URLRequest – never use NSMutableURLRequest in Swift 3 anyway – , just pass the URL and don't use URL as a variable name, it's a struct in Swift 3
class Downloader {
class func load(url: URL) { // better func load(from url: URL)
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig, delegate: nil, delegateQueue: nil)
let task = session.dataTask(with: url) { (data, response, error) in
// handle the error
// process the data
}
task.resume()
}
}

Completing webservice in background state iOS

Is there any possible way to complete a webservice task when ios application goes to background state using URLSession ?
I am not trying to upload a huge sized file to the server , instead i am trying to upload a 4 digit key.
i have tried the below method for background task.
var bgTask = UIApplication.shared.beginBackgroundTask(expirationHandler: {})
For testing purpose , i am calling webservice in a loop and logged. when i go to background mode the webservice calls are getting stuck.
Big upload/download files
Introduced in iOS 7.
It really depends on how much the task will take time. If it's a big download or upload task (for example downloading a video) you should execute the task using NSURLSession with background configuration. The iOS system will handle the upload/download task. Once the download completes, the downloaded file will be save into a temporary file (so you might need to copy it to another place later on). Downloading in background and waking app when finished
Normal WebServices (I think that this is what you want)
Introduced in iOS 6
For finite length operation, you can use beginBackgroundTaskWithExpirationHandler.
var task = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler(){}
//do your job (call the service)
//on completion you shouldcall the bellow two lines
UIApplication.sharedApplication().endBackgroundTask(task)
task = UIBackgroundTaskInvalid
No need to have configure an NSURLSession with a background configuration.
class func generalPost(url: String, postCompleted : (response: String) -> ()) {
let request = NSMutableURLRequest(URL: NSURL(string: url)!)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
let dataString = ""
request.HTTPBody = dataString.dataUsingEncoding(NSUTF8StringEncoding)
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
let strData = NSString(data: data!, encoding: NSUTF8StringEncoding)
postCompleted(response: strData)
})
task.resume()
}
And you can use
generalPost(url: "http://stackoverflow.com/") { (response) in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
UIAlertView(title: "Message", message: response, delegate: nil, cancelButtonTitle: "Ok").show()
})
}

NSURL completion event is not being called

I'm currently starting to learn swift.
My first "test-app" is a simple application, which does a NSURL Session request on startup and displays the received data in a tableview.
So far, my tableView does work and also my request method runs without any compilation errors.
My problem now is, that the event handler is not being called:
func doRequest(url: String) -> String
{
var url = NSURL(string: url);
var request = NSURLRequest(URL: url!);
var config = NSURLSessionConfiguration.defaultSessionConfiguration();
var session = NSURLSession(configuration: config);
var task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
println("CALLED");
});
return "";
}
The above method doesn't print anything into the console.
Since using google did not help me to find a solution, I try my luck here.
What's the issue with my code? Am I doing something wrong without realising it?
The URL for my tests is: api.football-data.org/alpha/soccerseasons/354/leagueTable
which returns a simple json object.
Any help is appreciated!
Add task.resume() to start the download.
After you create the task, you must start it by calling its resume method.
var task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
println("CALLED");
});
task.resume()

Resources