Start a free Courses trial
to watch this video
Forum Tip #10
This video doesn't have any notes.
Related Discussions
Have questions about this video? Start a discussion with the community and Treehouse staff.
Sign upRelated Discussions
Have questions about this video? Start a discussion with the community and Treehouse staff.
Sign upStudents are always trying to modify the blog 0:00 reader app, to repurpose it, which is great. 0:02 But working with real world data, you either have too much data or you're trying 0:05 to download images while on the same 0:09 time you're like scrolling the table view controller. 0:11 So that, you know, gives you a very choppy experience. 0:14 The code that we wrote in the blog reader project is synchronous code. 0:17 So let's try to understand what it's asynchronous versus synchronous. 0:22 And how we can write asynchronous code, 0:26 which is real world code, using NSURLSession. 0:28 So I've the Blog Reader course in front of me. 0:32 I'm going to scroll right down to the last stage which is Viewing a Web 0:36 Page and click on the last video which is Implementing a UIWebView'. 0:41 And let's go ahead and download these project files if you want to follow along. 0:49 All right so I've opened up the Blog Reader project and if you followed 0:54 along with the course, then you understand what's going on with the code over here. 0:58 Let me set a break point on line 45. 1:03 And let's run the application. So of course, 1:09 it halts at that line where the break point was placed and if 1:14 I, go back to the simulator as you can see the simulator is black. 1:19 That's because it's waiting for the information to be processed. 1:24 It's waiting for you to build that dictionary from the data 1:29 that has been downloaded so that it can finish drawing the view. 1:33 You can see the TableView, you can't 1:37 see the TableView. And over here you can see that it says 1:40 Thread 1, which is the main thread. It says apple, com.apple.main_thread. 1:44 So that's the main thread where all the UI Drawing happens. 1:50 You know, your, your UI views are loaded, you know, the sub-views are loaded. 1:55 All the drawing is happening on the main thread. 1:59 Which is a 2:04 simplest, I mean if you want to understand threading, it's 2:05 kind of like documenting multi-processes running at the same time. 2:08 It's a bit more complicated than that but think of it as a 2:11 cue, you know, you're cuing up tasks to happen and you have multiple threads. 2:16 And the main thread, most of the cuing happens when you're 2:21 like creating the window, you're creating the views, you're loading the views, 2:24 all of that is happening there. 2:30 So, when you're downloading data, you primarily don't want to 2:32 do it on the main thread or the main queue. 2:36 You want to do it on a separate thread, so that your view can still load and 2:39 the user can still interact with your application, while 2:44 the data is being downloaded on a separate queue. 2:48 So, lets, lets go, I'll go ahead and stop this. 2:51 Let me remove this breakpoint and I'll put a breakpoint 2:55 right here in the cellForRowAtIndexAtPath on line 83. 3:02 Right now, lets run this task or let's run this application. 3:09 So now, as you can see, once again, our our 3:14 app has halted on the main queue, you know, and there's 3:17 the main queue. 3:21 And the task is, or the method is self erode index path. 3:22 So if I go back to the simulator. 3:27 You can see that our simulator is black, you know, it hasn't drawn 3:29 the view completely because we you know, we don't have anything to show yet. 3:33 So, cuz we're waiting for us to download that image, so that 3:39 we can add that image to the cell, which can then be 3:42 drawn on the main screen. 3:46 So there's a lot of overhead going on over here. 3:49 You are simultaneously downloading data and trying to display that on the screen. 3:52 So, let's figure out how we can refactor this code. 3:59 So we can have a lot of asynchronous 4:03 data downloading happening while the view is being drawn 4:06 on the main thread. 4:11 So right now the, the code that we have is synchronous. 4:14 It happens synchronously where one task is being queued be behind the other task. 4:17 Asynchronous is when one tasks happens, while there is another task happening 4:23 in the background and then it comes back and joins the main queue. 4:29 Think of this as you know, lanes on 4:32 a highway. 4:37 If you had only one lane, then the traffic would go really slow. 4:38 But if you want the traffic to move faster, then you 4:42 can open up multiple lane son the highway, and that way 4:44 you can, you know, have more, you know, several cars driving 4:48 on the same side or, you know, in the same direction. 4:51 And you can have the traffic moving faster and faster. 4:56 Let's go back to our 5:01 viewDidLoad method. And let's, let's keep some of 5:02 this code. So we'll keep the blogURL because we 5:07 need that. We don't need this jsonData, we don't need 5:12 this, actually, let's keep a lot of this code and 5:17 I'm going to go down here. 5:24 And the class that we're going to use is NSURLSession. 5:26 Now this is a new class that came about in iOS 7. 5:31 This is called NSURLSession. So, 5:35 let's look at the documentation for NSURLSession. 5:39 I'll option click and look at the class reference and there's our NSURLSession. 5:42 As you can see it says, the class and related classes provide an API for 5:50 downloading content via HTTP. And it's a very rich API, it can do a lot. 5:55 And here, if I scroll down you'll see that the URL Session Class Hierarchy. 6:04 So NSURLSession is made up of several different classes. 6:09 It's not just one class. 6:13 So you have a URL Session. You have URL session configuration. 6:15 You have the task. 6:21 So there are several different types of task. 6:23 You have a data task. You have an upload task. 6:25 You have a download task. 6:27 The one we're gonna use is the, the 6:29 download task, cuz we want to download data 6:32 And then of course, it has delegate. 6:37 So if you want to overwrite some of the 6:38 methods, like while it's downloading or if it's redirecting. 6:40 Or you know, while the process is happening and if you want to hook 6:44 into any of those events, you can do that using some of the delegates. 6:48 So in order for us to use NSURLSession, we need a 6:53 URL object, which we have already, we have the blog URL, 6:57 we need a NSURL request, which we don't have 7:02 right now, but we'll see how to do that. 7:06 And we don't need any of these, I mean 7:09 we will get back a response cuz, we're going to 7:11 make the request so we get back a response 7:14 from the server so we'll See how that looks like. 7:16 And then there's a cached url response, we're not gonna look at that right now. 7:20 So let's go back here and 7:25 create a session first. 7:27 So we'll say session and in this URL session you can do shared session. 7:29 Which is a shared singleton object for the, for your app. 7:36 So you can create custom configuration sessions if you look at the documentation 7:41 for NSURLSession. Let me go back here, going back to 7:47 our documentation. So, Creating a Session. 7:52 So if I click on the left under Tasks here 7:57 and say Creating a Session, you have several different options. 8:02 You have sessionWithConfiguration, sessionWithConfiguration and 8:05 then, you know, you can 8:09 implement delegates or simply you can use a shared session. 8:10 And, and you can see here it says shared singleton session object. 8:14 So this gives you back some boilerplate session code 8:19 and you know, and that's usually good enough for you to use in most instances. 8:24 So, now that we have our session, we're going to 8:30 create our NSURLRequest, 8:35 okay? And the request basically 8:40 is NSURLRequest alloc init 8:45 and we'll say, initWithURL. Now, we already have a URL so, I am gonna 8:50 use that which is blogURL. Next I am going to create 8:56 an NSURLSessionDownloadTask. 9:03 [NOISE] So we create a task using the session 9:09 and we will use one of these methods here, so we use DownloadtaskwithURL. 9:16 Actually we don't even need to create the, the request. 9:23 The request can be automatically created for us, 9:26 all we need to do is provide a URL. 9:29 So let's use this one, this method here that says, 9:31 downloadTaskWithURL. 9:34 All right, so we'll provide this with the blogURL, now delete this NSURLRequest. 9:36 And then coming to the completion handler, all you have to do 9:44 is press Enter and then it'll fill the block out for you. 9:49 Now, before I go ahead and do anything with this block, let's put a semicolon 9:53 here and let's do NSLog and we will print out the, the response. 10:01 So as you can see we get three parameters to our block. 10:10 The first one is the location. 10:15 So this is the location of the data that has been downloaded for us. 10:16 And this is an NSURL so the data has been downloaded on the disk of 10:21 the device and it's giving the location, so this is not just like a web URL. 10:27 NSURL can also be a location 10:32 that's local on the file system. And then you have the response 10:36 and finally you have the error. So there's our response. 10:41 I'm gonna put a breakpoint here so you can see what, what happens. 10:48 We're still not deleting any of this code up 10:53 here so our, our app should work as normal. 10:55 And, as you can see, we get a warning and the warning says unused task variable. 10:58 That's because we have to do task resume. Whoops. 11:04 And what task resume is basically doing is it's just starting the task. 11:11 I know, it's called resume and not start, for some reason. 11:16 Who knows? 11:18 So, let's do command R to run our application. 11:19 And if I go back here, it, it halts the completion of our tasks but as you can see 11:24 here, it's, it's on a separate thread. 11:36 It's not holding up the main thread anymore. 11:39 So, it can draw whatever it needs to draw in the UI. 11:42 And there is our UI. 11:47 So that, that's what happens here, it's that the task is being 11:48 executed and the completion handler is being called later on, so that 11:55 it does not hold up the drawing of our UI. 12:01 Okay. 12:08 So, oh, by the way, I, I didn't show you the, the response. 12:08 So let's run this app again and here you have the, the response. 12:12 So basically it's just showing you you know, general information 12:18 of what the response was and how it was processed. 12:23 And HTTP status code 200 means that the response was successful. 12:27 Okay, so, what do we want here? Well, we can basically 12:33 take most of this code that we have 12:37 here and we can put it in our completion handler. 12:41 So let's copy all these code from line 38, where were parsing 12:46 the JSON and we will paste it here. So the 12:55 JSON basically needs, as you can see, it needs JSON data. 12:59 Now, previously, we were getting the JSON data just by calling NSData and 13:06 dataWithContentsOfURL, which is a synchronous way of getting the data. 13:11 It's not asynchronous. 13:16 So we'll, we'll delete all, these two lines because we don't need it. 13:18 So what, how do we get the JSON data? 13:22 Well, we need NSData, json data. So remember 13:24 I said we have our location, which is the location of where their data is stored. 13:31 Well, now instead of downloading it from the web, 13:37 we can just pick up the data from the disk. 13:40 You know, which, which does not take a 13:42 lot of time, It's, it's right there, it's local. 13:44 So we can say NSData alloc initWithContentsOfURL and 13:47 we can give it a location. And that's it. 13:58 Basically there's our there's our you know, there, there's our data. 14:02 And then the rest of the code remains exactly the 14:08 same, you know that, that part doesn't change at all. 14:11 So now if I run our app, you will 14:15 notice that the table view is blank, nothing is happening. 14:18 So let me, let me put a breakpoint here on line 51 and run the app. 14:24 So, as you can see, our UI has been drawn and we earn a separate thread. 14:29 So this operation is happening on a separate thread. 14:37 Our main thread is not being held up and then we 14:41 are like, parsing the data and massaging it and putting it in 14:44 whatever format we need to put it. Now why is our view not being drawn? 14:49 So, remember I said this is a separate queue and 14:54 the, all, all the UI drawing happens on the main queue. 14:59 So this is the only part that's a bit tricky, 15:03 we need to send a request to reload the TableView. 15:06 So, I could just do this here, let me scroll this up. 15:10 If I 15:14 could say, oops, self.tableView 15:14 reloadData. I could do that but 15:19 nothing will happen. Our table views will still be blank, so, 15:25 instead what we have to do is call dispatch async. 15:30 [BLANK_AUDIO] 15:35 And what is that? Well let me. 15:37 [BLANK_AUDIO] 15:39 dispatch_async, and [NOISE] basically 15:43 this is a way to send a request to the main queue 15:47 that you want to do something on the main queue. 15:52 So how do you access the main queue? Well, you have to call 15:58 dispatch_get_main_queue. 16:02 As you can see, these are C functions and you get back a block. 16:08 And so, basically, you're saying, make a call dispatch a 16:12 request to the main queue and execute this piece of code, whatever that code may be. 16:19 So, in our case, that code is basically reload data. 16:25 So, any of view drawing or updating that you need to do. 16:33 You need to do it on the main queue and then 16:37 you call table view reload data and there is our data. 16:39 So there you have it, we just 16:45 converted our Blog Reader project to be asynchronous. 16:47 And this is of immense value and you should probably do this going forward 16:50 for most of your projects, where you want to download data and process it. 16:54 Very seldom that you should use synchronous way of downloading data. 16:59 So the next thing we wanna do is improve our image downloading. 17:05 So in our cellForRowAtIndexPath, where we download the image and display it. 17:10 Here once again, this is a synchronous way of downloading data. 17:15 We should change that to an asynchronous way of downloading data. 17:19 So let's see how we 17:24 can facilitate that. All right, so, let's go ahead and remove 17:24 these two lines of code. Actually, we just need to remove 17:29 this one line of code and, we'll go 17:36 ahead and do a NSURLSession. And then NSURL, 17:42 NSURLSession sharedSessio, and then 17:49 we need to NSURLSessionDownloadTask 17:55 and once again, we use our session 18:00 object. And we'll say 18:05 downloadTaskWithURL, and where do we get the URL? 18:09 Well, remember in our blog post model, we created a method called thumbnailURL, 18:14 so that's where we get our URL. And once again press Tab and 18:21 Enter, so you can have your completion handler block. 18:27 So for our code, once again, we'll get our data. 18:32 We'll say data equals and 18:36 NSData alloc initWithContentsOfURL which is 18:39 location. And now, we can take this line 18:46 of code, actually both these lines of code and copy them in our completion handler. 18:53 So, we can change this basically instead of 19:00 imageData or we can change the name of our 19:02 variable here. 19:05 We can call it imageData so its kind of clear what data is coming to us. 19:05 And then, for us to store the imageView 19:11 or store the image in the imageView, once again, 19:17 we'll have to call dispatch_async, because that's view 19:19 operation that should be occurring on the main block. 19:23 So let's go up here and copy this line where 19:26 we do the dispatch_async. 19:30 We'll copy that and instead of calling tableView reload we'll simply 19:35 copy our cell.imageView.image. 19:40 Now, do not forget to you know, call task resume, so we're gonna do 19:45 task, resume here. 19:50 All right, and let's run our app. 19:56 And our thumbnails don't show up. So there, there is one thing to 20:01 consider here, the property imageView is, as 20:06 you can see it says, read only. This is a lazy loading way 20:12 of defining your views. And what do we mean by lazy 20:17 loading? Well, it's not created until it's needed. 20:22 So, it's created over here because you're setting an image. 20:29 But in our case we are not, when we're returning this 20:35 cell, so when you're creating 20:39 this cellForRowAtIndexPath you're returning your cell. 20:41 So, when you're creating and returning the cell, you're saying 20:45 like well, I need an imagery and I'm setting it here. 20:49 But in our case, the imagery 20:52 is not being created until the completion handler block is called, until much later. 20:54 So, we are returning the cell, but we are not setting an imagery whatsoever. 21:00 So instead of setting an L statement, we're going 21:05 to delete or we're going to cut this cell.imageView. 21:09 We're not going to have an L statement. And right here, 21:14 before our if statement, we'll always set the treehouse.png as a default image. 21:18 So we'll create an imageView and return to cell and then we 21:25 can override the, the image property of our imageView. 21:29 So let me run the application so you can see. 21:34 So now it all works. 21:37 You know, now you can see images in all of the rows. 21:38 So, basically we're instructing that, hey, we 21:44 need an imageView when we're building this 21:47 cell and then we'll tail, change the image out latter when we download the image. 21:50 And if doesn't download a new image, then, by default, it 21:54 will always show the, the Treehouse logo which is what we want. 21:58 So, it works, it works out perfectly for us. 22:03 So there you have it. We've changed our, 22:06 blog reader, project to download data in asynchronously. 22:09 We've changed our cells to download images asynchronously. 22:14 And the benefit of doing this is two fold. 22:19 One is you don't block the UI, so that the user can still interact with the UI. 22:22 And secondly by downloading your images 22:27 asynchronously, you don't get choppy scrolling. 22:29 You know, so you're not downloading images while the user is scrolling. 22:34 The downloading of the images happens in the background so the user 22:38 has full access and can interact with the UI, as they normally would. 22:42 >> Hope you now have a better understanding 22:49 of how to download data asynchronously using NSURLSession. 22:50 I would definitely make this the default 22:55 way of downloading data in future projects. 22:57
You need to sign up for Treehouse in order to download course files.
Sign upYou need to sign up for Treehouse in order to set up Workspace
Sign up