URLSession Tutorial: Getting Started | raywenderlich.com

In this URLSession tutorial, you’ll learn how to create HTTP requests as well as implement background downloads that can be both paused and resumed.

This is a companion discussion topic for the original entry at https://www.raywenderlich.com/3244963-urlsession-tutorial-getting-started

Hello @Audrey, @kentoh, can you explain the use of [weak var] in the code snippet below? Why is weak self needed at all? If it is definitely needed to not get into a strong reference cycle, would unowned not be better?

Thanks in advance!

// 4
if let index = download?.track.index {
  DispatchQueue.main.async { [weak self] in
    self?.tableView.reloadRows(at: [IndexPath(row: index, section: 0)], 
                               with: .none)

Hi Christopher, it’s in our Swift style guide: GitHub - raywenderlich/swift-style-guide: The official Swift style guide for raywenderlich.com.

But there should also be this guard statement to avoid optional chaining:

 guard let self = self else {

Hi @audrey, thanks for the quick reply and link. I still don’t understand where the need of [weak self] arises as I cannot see where the strong reference in this closure is located. The closure itself is not referenced as a property of the class itself, which I understood from Apple’s Swift programming guide to be the reason for strong references in closures.

I found this explanation: it seems it’s more a case of not reloading the row if the view controller has been released.

actually, Felipe / @airjordan12345 added that weak self so he’ll be able to explain it better :wink:

I believe @Audrey is correct. If we have already release this controller then we don’t do anything due to the optional chaining. To do things without the optional we’d do he if-let unwrap as mentioned before.

While I see why some people prefer unowned as it removes optionality, I always go for weak because there is always a chance that self has been released by the time you get to your closure. If that’s the case, unowned will cause a crasher as it’s not optional, where as with weak you may simply not get past the guard statement or the optional chaining.

You’re certainly free to use unowned if you are fully aware and comfortable with your object’s lifecycles :slight_smile:

1 Like

Is there no smarter way than dynamically allocating a custom URLSession in the ViewController if I need a delegate? Isn’t there a memory leak in this case because neither invalidateAndCancel() nor finishTasksAndInvalidate() is called on the dynamically created URLSession in the SearchViewController.

If I have multiple ViewControllers which all need the same URLSession configuration but each of them has to be the respective delegate, is there a way to define a “global URLSession” that automatically adapts the delegate to the ViewController that is currently creating a DataTask? Being able to store this type of URLSession as a static shared property of the URLSession class would be even better…

@airjordan12345 Can you please help with this when you get a chance? Thank you - much appreciated! :]

The URLSession is not dynamically created every time we use it, it’s created once, when needed, and then we reuse the same session unless a new instance of this controller gets created.

Since that means we’re not losing the variable or reference to this session, then canceling or doing other operations on the session won’t result in leaks.

As for having different delegates. A single session can only have one delegate, so if you are looking at using URLSession with delegation and not completion-based calls, then only one object can be its delegate. You could create a global configuration and reuse it in different controllers that have their own URLSession, alternatively you could also create a manager or helper class that has a URLSession, a delegate (unless using completion-based data tasks), and then just performing new data tasks or network requests with it.

In my experience, completion-based calls are better than delegates for this last example. You can use your networking layer and simply handle things in your completion handlers wherever you make use of a network call.

Hope this helps :slight_smile:

Hi @Audrey, thanks for cool manual but I can’t understand how can I catch an error at bg download task?

Hey, thanks for the quick link! very useful

hi Max! you could change the print statements to write the error messages to a file?

Hi, the following query
urlComponents.query = "media=music&entity=songs&term=\(searchTerm)"

returns response with status 400 with following body:

“errorMessage”: “Invalid value(s) for key(s): [resultEntity]”,
“queryParameters”: {
“output”: “json”,
“callback”: “A javascript function to handle your search results”,
“country”: “ISO-2A country code”,
“limit”: “The number of search results to return”,
“term”: “A search string”,
“lang”: “ISO-2A language code”

I changed the query to
urlComponents.query = "term=\(searchTerm)"
and I got the response status 200 with app showing the results. Please update for posterity. Thanks. Very useful tutorial though. :slight_smile:

thanks Hasaan!

but I just sent this url and it worked:


the api lists media and entity as valid parameter keys, along with term

unless there’s a different set of keys for some countries? where are you located?

but it would be very strange …

I’m located in Pakistan. Well I opened the url you mentioned in my browser and it downloaded the .txt file with valid results. But it didn’t work in the app with this query. Strange. May be we should keep the query as it is but add some note that for some regions try alternate api query. I thought other people might also be facing this issue. Thats why I posted it on the forum.

thanks Hasaan! the error message you got indicates something different about how the API works for your location or internet provider. I’ll add a note.

This tutorial is more than six months old so questions are no longer supported at the moment for it. Thank you!