[MUSIC] In this video, we're going to learn how to asynchronously download images and JSON data from the Internet. The images will come from Flickr's public image feed, which is updated continuously throughout the day with new images. JSON data is a text based data format similar to XML that is used by a great number of web services as a format for transferring data. We'll learn how to de-serialize this data into Swift objects. In this video we're going to look at downloading data and images from the Internet using the NSURLSession API. We're starting with the project that we were working on before, but I've made some changes to the project first, just to get ready for this session. We're not going to use the original view controller anymore, I've actually created a new one. It's the ImageFeedTableViewController, and it's just a subclass of the UIViewController class. So it's pretty basic right now, we're just implementing really three of those tableView functions. So we just have numberOfSection, and there's numberOfRowsInSection and cellForRowAtIndexPath. We also have a special subclass of the UITableViewCell. So each row in our table view is going to show an image and a title for that image from the Flickr public image feed. And to represent that, our cell will have an outlet to an ImageView and a Title. Lets go over to the storyboard, and you can see how this laid out. So we have a prototype cell. That's an ImageFeedItemTableViewCell, and as you can see it has an Item Image View and an Item Title. And those are both kind of laid out in a stack for you just to help space them out horizontally in the table view cell. And then, you can see here if I right click, it has a couple outlets that are connected to these two, I'll just zoom in there so you can see it. So there's the ItemImageView, and the ItemTitle are connected from that cell's class. So the ImageFeedTableView also has a reference to a feed. So this is the model, this is where the data actually comes from. Let's take a look at that feed class, and I've added a feed class that represents a list of items that are found in a feed of images. All the items are stored in this array and it's an array of structs called feed items. If I go over here, you'll see that each item has a title and an imageURL. So that's the source if I were to download the image. And if we go back, there's also a sourceURL for the feed itself. You probably remember how in settings, we had three URLs that the user could choose from. So we're going to remember which URL was the source of this feed when we actually, it's going to remember which URL was its own source. So this is just going to store that in this property. So you saw that that image feed table controller had a reference to that feed, so I'm just going to scroll down here quickly and you'll see that it uses the items. So it gets the count of rows from the count of items. And for each row it's going to load a particular item for that index, and it's going to set the title to that struct's feed item's title. So we have our model class, but where is the data actually going to come from to be put in to create that feed? Well, Flickr actually offers a public API of continuously updated recent images, using JSON format, and you can simply access this API by loading a specially formatted URL. And you member, like I said, we added those URLs in the previous video. But JSON is a text-based format so we can actually load this in our browser and take a quick look at it. So I'm just going to double click on one of those URLs in the settings bundle and we're going to go back to the browser and open a new window and just paste that in there. And download it so that, it's a bit small here but you can see, this is text-based data and like I said it's a little bit like XML to some degree really, but with a much more simplified syntax. It's also similar to plist files, and that it can store arbitrary values like strings, numbers, arrays, dictionaries, and all these values will be accessed using keys. So each value is associated with a key. So for example, you have this bracket here, represents like a top level dictionary, and then it has a series of keys and values within that dictionary, so here we have the title for the feed, and then it has the value for the title there, which is a string. And then, some of these keys actually refer to arrays, so this square bracket represents like an order the ray of items. And each of these items is again another dictionary within this scrub brackets with some more titles and values. And this what we're really looking for. We're looking for these titles. Like this at the image titles. And then, under media, this is the image. This is the link to where you actually download that image directly. To work with this, what we'll be doing in the app is downloading it when the app starts up. But before we get into creating that download code, let's just save this file as an example that we can load with our project, sort of like a static, a sample data file. And it allows to kind of play with that JSON serialization framework in order to decode this into swift objects without having to worry about downloading it within our app. So I'm just going to save it, Cmd+S, and go to page source as the format and just click Save to the desktop. And then, I'm going to close that. And open up finder here. Find under desktop. Just drag that into my project here and copy it. So now we have our data in here. So for now, for this first part, we're just going to load this using the sample file that we have on our project. So now that we have this data in our project, let's add a convenience initializer for the feed class so that we can take this JsonData and translate it into swift objects. To find all those image URLs and titles and populate the fields of those feed items struts and fill out that feed items right here. So what I'm going to do is just fill in the initializer here. There we go. So this is a pretty big convenience initializer, and what it does is it takes an NSData object that contains that JSON text, and it also takes the source URL of where this feed came from, and then it starts out here with an array of feed items, and it's a blank array. That's a mutable array that we're going to put all those feed items into. And then, we're also going to fix that data, so this is just a little detail here that because of the Flickr data, there's some weird characters in it that the NSJSON serialization class doesn't like. So I just created this little simple fix.JsonData function that's going to remove some of those funny little characters and in that way we'll be successful in translating our JsonData into swift objects. So the first swift object that we're going to back from the JSON serialization initializer is the dictionary. And it's going to be a dictionary of strings and any objects because our JSON dictionaries can maybe hold either arrays or it can hold Other dictionaries or strings or numbers so what we're going to get back is initially just going to be a dictionary of strings and any objects. So we initialize this JSON object by trying to load the data using the JSONObjectWithData method. And that takes our repaired data and we're going to cast it into that type that we're expecting for the JSON object variable. If it doesn't exceed it will likely return nil. And it will likely raise an exception here. We're just ignoring that exception for now and if we do get nil, if we can't cast this JSON object into a non-optional variable feed route, we're actually just going to return nil and this feed will not be initialized properly. Okay, so this JSON object is a dictionary. And actually, sorry, we're going to use feedRoot now. So this feedRoot is a dictionary and it can be indexed by strings. So each of those strings that are act as the keys for the dictionary actually map now to the strings that are in the top level dictionary of the JSON object. So, if you want to look at the title of the entire feed, you would look for the title key in that dictionary. We want to pass by the title of the feed itself and look for the individual items in the feed, so we're going to look for that items string, and under that it's actually an array. So we're expecting an array of items. So if I go back here and look at the array, we'll see that we're hoping to get this items and cast it to an array of any objects. If it doesn't succeed, if it comes back as something we're not expecting, again, we're going return nil. So this is an advantage of Swift's static typing, is that it's easy to make sure that you're getting the objects that you're expecting before it becomes too late. Okay, and then after that, what do you do with arrays? Well, you generally iterate through them. So we're going to iterate through each item in the items array. And then each item itself is going to be a dictionary, just like our top level object is a dictionary. Again, we're going to look for another dictionary, but each of these items is going to be an individual photo with several properties. To find the image URL, we have to look through the media and the n keys, so if I go here and look through here, there's a media key, and under that, there's an n key. And then under that, there's an actual string that is that URL. If we find both of those, we're going to try and translate that URL into a proper NSURL. So if that fails, we're just going to skip it, but if it succeeds, then we have that URL for our FeedItem class, and we're also going to try and get a title as well. So, once we get the title and the URL for each of those items, we're going to construct a FeedItem struct, and give it the title, or a default title if it doesn't find one. And we're also going to give it that URL that we found. And then finally when that is all done, our newItems array has been filled up with all of those feed items and we're going to just pass it off to the designated initializer along with our original feed URL as well. Okay, so that's the long process of turning JSON sterilized data into Swift objects. So really, the difficulty of this is that you don't really know if you're going to be missing values or not. You always have to check to make sure that you're not getting nil back when you expect to have a value, and that it's actually the kind of object that you expect as well. Okay, so the next step is to kick off this initializer in our AppDelegate, so that we can actually load the data and hand it off to our ViewController. So I'm going to switch over to the AppDelegate here, and then I'm going to add a function to load that data. It's just going to be called updateFeed. We're calling it updateFeed for now because eventually we're going to use this to actually download the JSON data from the Internet. But for now, we're just going to load it from the main bundle. Finding it using the URL for resource. So this just going to find that file that we're going to store in our bundle. So this file here. And we're going to give that URL to NSData. NSData's contents of URL function can take a URL from a local data file and turn it into an NSData object in memory. And then we're going to take that data file and give it to the feed object. This function also takes a completion block, and the completion block is something that will be run once that feed item has been loaded. Okay, so we're going to make one more change here, that's in the applicationDidBecomeActive function, and that's going to actually kick off that update feed whenever the app becomes active, so just going to add that. Let's go here. Okay, so. Whoops. [INAUDIBLE] the early one. Let's go back. We want the newer one. Okay, add this stuff here. Okay, so we're still getting the URL string from the StandardUserDefaults. So we're still loading that URL from the settings that the user has chosen. But this time, let's see here. We're actually going to make sure that we did get a URL string. Otherwise, we're not going to do anything, because something went wrong. And under here, let's take a look. We're going to try and turn that into a legit NSURL item. And then we're going to call that updateFeed function on our class. And we're going to give it a completion block. And this completion block is called when it's done loading that feed. And it gets the feed that is loaded, and it's going to assign it to that view controller. So it's going to find the view controller under the sort of global application object. And we're going to assign that feed. And if you remember in that view controller, when it has this sort of a monitor here that whenever it gets set, it's going to call reloadData. So once we've loaded that data, the feed is going to be shown on the screen. So let's actually try that out. We've added just a couple things here. We've added that initializer and we're going to update and load our feed every time the app starts or is reloaded. So we're running the app here. Okay, and then you can see we're getting a whole bunch of rows of whatever people are uploading. Who knows, this will probably be different for you, if you go and download stuff from Flickr. You might find out there's something different there, but it actually is loading those titles. So the next step is going to load some images from the feed and update the feed each time the app starts. All right, so we have got the data. We've deserialiazed it using the JSON serialization into Swift objects. And we've got a feed, and we've got a list of feed items, and we've got URLs. So the next thing to do is actually to download those images and show them in the table view. So we're going to update this table view controller with some stuff for actually loading these images. Okay, so we're going to use the NSURL session API. So let's create a property here in our view controller to hold a URL session object. Let's see. URL session. Okay, so, this property holds a NSURLSession object, so an NSURLSession is an object given to you by the system or that you create that keeps track of all of your downloads. So it can host and manage multiple downloads in the same context. So you create one URL session for a particular configuration or a bunch of downloads They can be multiple requests, but, generally, they all have the same type of caching and configuration type requirements. Okay, so we got a property to hold this. Let's add a method to create that when the view appears. Put that there. So, to create an NSURLSession object, you have to give it a configuration. And then to create a configuration, you can either start with a blank configuration, or you can use the defaultSessionConfiguration. That's a class method under the NSURLSessionConfiguration object. And this configuration contains things like cache settings and other things that tell the system how to handle URLs. The default session one will just use the default cache, and use the default, and some other defaults and we'll just stick with that, that's fine. So, we hand that to the URL session constructor, and then we get back a URL session instance that we're going to save in our property. Okay, next step is to just, since we've got something to create that, let's put in some code just to destroy it when we don't need it anymore. So, I'll just put in some code here, so when the view actually disappears, what we're going to do is call this invalidateAndCancel, and that's just going to basically cancel any outstanding downloads, right? You don't want to keep downloading images if the app closes or you switch to another story board. You want to stop all of those image downloads. And then we're just going to zero it out when it's done, so that we don't accidentally try to reuse it. Once you invalidate and cancel a urlSession, you have to basically stop using it after that. Okay, so we've got our context. The urlSession is kind of a context for all the actual downloading. Let's actually add the code to download it. And what's going to happen is when each cell is loaded into the table view, that's when it's going to actually kick off downloading that image. Why are we doing it this way? Well, imagine you had 500 images or 1,000 images, who knows how many images are going to appear in this feed? You don't want to download them all at once, you want to download only when they're needed, right? So, I'm just going to add that code here, just kick off a download for each cell when it's created. Let's see, and we'll just go through how that works. Okay, so I've added a bunch of code here. There's a couple errors, we'll fix those in a sec. So, what this does is it creates a request. An NSURLRequest is sort of an encapsulation object that includes a bunch of other information that That you need to send off with the request beyond just the URL. So URL is just the location of the item. A URL request includes things like the method, the HTTP method that is called upon the server. Any sort of login, metadata info that you need to send with the request. That's all encapsulated within NSURL request. You can create one just with the URL though. So we take that image URL from the item, and put it into an NSURL request. Then we're actually going to use our URL session object to create a data task. So the URL session object actually can vend or create these tasks, and a task is kind of like a simple, single download operation. You give it the request, and you give it a block that it calls when the request has been completed, and it will give you back some data and the response from the server. And if there's an error, it'll give you back the error message as well. You can log that or display that just to keep an eye on, if you try and figure out why your server is not responding properly. We're going to assign this to the cell, and I haven't created a property yet on the cell, that's why there's an error here, but the cell is going to keep a weak reference to this URL Session, just so that we can cancel it later if the cell disappears. So, when that session has downloaded its data, it's going to call our block, and in our block, we're going to check to see if there's an error, check to make sure it actually gave us some data, and if everything looks good, we're going to use the UIImage to turn that data into an image. So we're actually expecting that data to to be an image. As long as that works, we're going to set that image to the item image view and then it will actually display it on the screen. This is all wrapped in NSOperationQueue called so, this is going to call the main queue with this. We don't know, necessarily, what thread this block is going to be called on. So I just wrap this in a main queue add operation call here. What that does is it makes sure that this is always called on the the main thread and the reason for that is that you need to- the rule is, you should never update your user interface on another thread other than the main thread. So, this is just a very quick and simple way to make sure that any time that this code call comes back from the URL session, it is actually going to be called on the main thread. Then, the last thing to do is to just call resume. So that task, once you created it, it doesn't actually start downloading until you call resume. That's something you'll always have to remember. That's something I often forget, I wonder why my data tasks are not downloading and it's probably because I just forgot to call resume after creating them. Okay, let's just fill in that last little property on cell and then we can run. So I just want to make sure I have a property for that URL session so, let's create a weak there, and it's going to be an ASURL session data task, that's the type that it's going to be. Okay, and we're just waiting for Xcode to catch up here. Okay, and you'll notice that I've created this as an optional. That way, it won't complain about not being initialized. Anyway, so we've got rid of those errors, and we can actually build and run and see what happens with our images. So hopefully they will load. So it's just starting up. Switch over to the simulator. There we go. And our little kittens are loading up here. Just a quick trigger warning, this is a public data feed, right, so you don't know what images people are loading. So you might get completely different images, maybe nothing to do with kittens. So, just be careful with what tags you choose because you will just get bad random images based on whatever tag In whatever people are uploading into Flickr, right? This is a uncontrolled data feed. Anyway, looks like our images are downloading properly. Okay, so now these cells, every time they're displayed, they start a new data task and they start loading that image. Now, you might remember that the tableView recycles its cells. So, as you're scrolling through tableView, those cells are going to disappear, and then they're going to reappear as something else. So, that cell might disappear at any time, it might even disappear in the middle of downloading something. So, you're going to get images appearing randomly that, if they load in a different order or something, they might appear over top of previous images that are loading. You don't want to have multiple things loading at the same time for cells, so let's cancel that if the cell is actually going to be recycled. So we're just going to enter another kind of of protocol method here that's the dead end displaying cell and that's going to cancel the image from loading. So let's just spell that in here. So, this is just a one of the Protocol methods that gets called. It's a call back that's called from the table view whenever it finishes displaying a cell. And we're going to get that reference to that data task and we're going to cancel loading that. So that's just going to sort of reduce the chance that we're going to have any kind of multiple requests per cell. Okay, next, let's start loading the feed as well. So we've loaded the images. Now instead of using the static feed, we're going to update the feed from the online source. So I've gone back to the app delegate file and we're going to delete that update feed method. And we're going to replace it with a new one that's going to load the feed from an online source instead of locally. Let's scroll here. All right, so here we have this updateFeed method that's a little bit bigger. Has the same parameters, it takes a URL and a completion block. But this time the URL is going to be turned into an NSURLRequest and we're going to use that to create a data task. This time, we're not using our own custom URL session, we're actually going to use a shared session. This shared session just uses default settings. It doesn't allow you to configure it in any way, but it's really fast and easy to create. And then in the callback, we're going to create a feed object from the data that it gives us. And then on the main queue we're going to call that completion object and update the viewController, which is in this block here. So let's run that and hopefully this time we'll get some different stuff. Okay, so now we are getting pugs instead of kittens. So that's because the data feed is being loaded on the fly instead of loading from our kind of previous file here that we had, the static file. If I go into the settings, I'm might have to actually quit that. So if I go into the settings, I can actually, I should be able to quit. Or I should be able to change the setting, change to a different feed and go in here and it will load now the kitten's feed. And we'll see we're getting kind of random images here. That's just because people are, you know, tagging their images as kittens instead. I don't know why this bicycle is tagged as that, maybe because there's a kitten at the background there. Anyway, just go back here, we can go back to pugs, go there, and it will update again. It's always going to get the latest data from online. It's not just loading it from our static file. So that is loading data using NSURLSession. You saw that there are a couple of different objects in play, there is a configuration object, there's the session object, and there's a task object. So you use the configuration object to create a custom URL session, and then you get data tasks from that URL session to actually download the files. If you don't need to do a custom configuration, you can actually just use the system-shared URLSession as well. That's a little bit simpler. Okay, in the next video we're going to show how to store this feed object, so that you don't have to download it every time you start the app, which will save us some network access and bandwidth. Okay, thank you very much.