Reputation: 1051
In a nutshell, I am trying to display data from a publicly available JSON file on the WEB. The process is the following:
I initiate the download with an NSURLSessionDataTask
, then I parse and display the JSON or handle errors if they occur. Here is my relevant code:
- (void) initiateDownload {
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfig.timeoutIntervalForRequest = 5.0f;
sessionConfig.timeoutIntervalForResource = 20.0f;
NSURLSessionDataTask *downloadWeatherTask = [urlSession dataTaskWithRequest:urlRequest
completionHandler:^(NSData *data, NSURLResponse *response, NSError *downloadError) {
if (downloadError) {
dispatch_sync(dispatch_get_main_queue(), ^{
[self errorReceived:downloadError];
});
} else if (data) {
dispatch_sync(dispatch_get_main_queue(), ^{
[self parseWeatherJSON:data];
});
}
}];
[downloadWeatherTask resume];
}
I have a couple of questions about this:
I am not all that familiar with thread handling. Although I added the
dispatch_sync(dispatch_get_main_queue(), ...)
to both completion blocks, and it seems to work, I am not sure this is the best way to be thread safe (before, I received all kinds of error messages and displaying the data took 10 seconds after the download has already finished). Is there a better way to handle the download and the threads or mine is an acceptable solution?
I would like the user to be able to initiate the download process manually any time he/she wants to refresh the data displayed. At first, I initialized the NSURLSessionDataTask
once and made it available anywhere within the class; so I could just call resume every time a refresh is called. However, I could not find a command to re-do the download process. Once I called [downloadWeatherTask resume]
, I was unable to start the task from the beginning.
So, I added the task to a separate function (the one you see above) and initialize it there every time the function is called. This works fine, but I am not sure it is the best way to go. For example, is it memory safe or am I creating a new task every time the user initiates a refresh call and will eventually run out of memory?
Thank you for the answers!
A little more info: I use the latest XCode 11 and target iOS 9 and up.
Upvotes: 2
Views: 362
Reputation: 437622
NSURLSession
will, by default, use a dedicated background serial queue for completion blocks (and delegate methods, should you do that). But you really want to make sure you trigger UI updates from the main queue (retrieved via dispatch_get_main_queue()
). And you generally want to avoid updating properties and ivars from multiple threads (unless, they have some thread-safety built in to them, which is unusual), so dispatching the updates to those properties/ivars back to the main queue is a nice simple way to achieve thread safety.
So, bottom line, what you’re doing here is fine.
However, I could not find a command to re-do the download process.
You perform (resume
) a given task only once. If you want to perform a similar request again, instantiate a new NSURLSessionDataTask
.
Upvotes: 2