This workshop will be retired on May 31, 2020.
Main Queue vs Background Queue12:37 with Amit Bijlani
Queues are lightweight data structures that manage objects in the order of First-in, First-out (FIFO). The main queue is primarily used for UI related tasks while background queues are used for everything else like downloading data from the network or other time consuming tasks.
So I've created a sample app that downloads images 0:00 from the Mars Rover using the NASA API. 0:04 And as you can see, 0:07 you can access images from the various cameras of the Mars Rover. 0:08 And here's what the JSON looks like. 0:13 You have a photos array. 0:15 Inside each photos array you have a dictionary that contains 0:18 a lot of information about that particular picture. 0:22 It has the date, the camera, a little more information about the rollover 0:25 what it was doing at that particular time, then of course you have the image. 0:31 And for example this is one of the images from the Mars rover. 0:38 It looks pretty cool, doesn't it? 0:42 What I did was I created a sample app that displayed each individual image in 0:43 A TableViewCell. 0:48 Now the app is not optimized for concurrency, so 0:50 let's run the app first and there the app is doing 0:55 something there's a blank screen and then the images come up. 0:59 Obviously this app is not optimized in any way to a way to take advantage of 1:05 concurrency. 1:09 The first problem was that we get a blank screen. 1:11 The user doesn't really know if there's something going on within the app. 1:14 The second problem is once we scroll, the app seems to stutter. 1:17 It's like we're forcing it to scroll. 1:23 Basically what's happening is that our image download code is blocking 1:28 the user interface. 1:32 We've seen enough, let's take a look at the code to see what's going on. 1:35 We of course have some mean classes over here we have the PhotosTableViewController 1:39 which is essentially just a subclass of UITableViewController and it contains this 1:45 mutable array of photos off type photo we've created a struck called Photo and 1:51 right away I am calling this method that says LoadPhotoSync. 1:58 It's synchronously downloading the JSON and parsing it, and 2:03 creating an array of photos. 2:07 Before we take a look at the table view cell and what's going on there. 2:11 Let's take a look at this loadPhotosSync. 2:15 I'll just command click here. 2:18 And, essentially this takes us to the photo.swifts and 2:21 here I have the API key in the base URL. 2:27 We have a type alias called JSONDictionary which is basically a string and 2:31 any objects in swift three, it's just called Any. 2:35 We haven't enum for error so when were parsing this dictionary and 2:40 if we don't get the value that we need, we throw in her for now our photo struct 2:46 has only one property which is called imageURL, it doesn't have anything else. 2:53 Of course we could have just created an array of strings but 2:59 I wanted to give a more concrete example. 3:03 In this case you could have other properties within your struct. 3:05 And here we're parsing the dictionary, and 3:10 finally we have this extension where we have our loadPhotoSync. 3:14 I've created this static variable called you URL components that takes a base URL 3:19 and adds query parameters and then simply returns the URL. 3:24 The loadPhotosSync essentially just gets the Data using this contentsOf URL. 3:30 And then parses the JSON, and then finally goes through each one of the dictionaries, 3:38 and basically, delete that there, and 3:44 basically creates the photo struct and appending it to this photo's array. 3:49 And just returns it. 3:56 We can create a break point here and run the app once again. 3:59 You will notice that each line of code is synchronously executed, which 4:04 means that it does not move to the next line until the previous line is executed. 4:09 You can step over here, and as you can see it just moved on to the next line of code. 4:15 See here it is downloading the data, and 4:21 then it comes back with the downloaded data. 4:23 As you can see it executed synchronously. 4:26 The other thing that you will notice here in the breakpoints navigator, 4:29 right here you'll notice that it says Thread 1. 4:34 If I expand this a little this is our main thread. 4:38 You see it says here com.apple.main thread. 4:43 This is the main thread or the mean queue it says Thread 1 Queue. 4:46 The main queue is mainly responsible for the user interface and 4:53 listening to user events like gestures, tabs, scrolls. 4:56 If we execute a task on the main queue, 5:00 then it blocks the user interface until it is finished. 5:02 Asynchronous task does not finish until it is completed. 5:07 Which means if a task takes 30 seconds to finish, it will keep blocking 5:10 the UI until it is finished because this was evident when we ran the application. 5:15 If we step through this code, you will notice that it stays in the main queue. 5:21 Of course, it's gonna go through the entire dictionary and 5:27 finally return photos. 5:31 All of this is done on the main queue and it's done synchronously. 5:33 So overall terrible code is just terrible to do everything on the main 5:38 queue because if this downloading and 5:43 parsing of data takes 30 seconds or even a minute our UI will be blocked and 5:46 of course we saw that when we had this blank white screen. 5:51 So let's stop this and let's see how we can make this more efficient. 5:58 To asynchronously request data from the server and 6:04 to free up the main queue to listen to user events we can use NSURLSession, 6:09 which will run a task in a background queue unless it is specified otherwise. 6:13 Now you've learned a little more about using NSURLSession and 6:18 then background queues in 6:22 a networking with swift course which I will link to in the teacher's notes. 6:25 If you want to learn more about it in this URL session, 6:30 you can refer to that course we're not gonna dive deep into that over here. 6:33 But I will write another static 6:37 function I'll say loadPhotosAsync, 6:41 now we'll provide it with the completion block, 6:46 where we take a photos array, and 6:53 we don't return anything. 6:57 All right, so using our swift three syntax. 7:06 We have to do URLSession, so shared session, dataTask, 7:10 and we want dataTask with URL and completion handler. 7:16 Our URL is urlComponents.url. 7:21 Where did we get that from? 7:27 Well we have a property called urlComponents in our extension of photo. 7:28 And then the completion handler. 7:34 If we hit Enter, it will basically provide us with this template 7:36 where we have data response and error. 7:42 And then of course our code. 7:50 Essentially we can reuse all of this code that we have in the loadPhotosSync. 7:53 I'm just going to copy all of these code here. 7:59 And paste it inside our data task block. 8:03 And instead of getting data from the Web, we'll simply use this 8:08 argument that's been passed to us in our block by the URL session. 8:13 So we'll unwrap that optional. 8:21 And the rest of it remains pretty much the same. 8:24 Here we have to call a resume task. 8:27 Because we're creating URL session tasks which needs to be resumed. 8:31 I still don't understand why it's called resume but 8:35 that's how you kick off the task and instead of returning the photos array, 8:39 we have to pass it to our completion block. 8:43 We'll say return completion photos. 8:47 That's how we're going to pass that array that we have created right here. 8:52 Back to whoever is calling this method. 8:57 So we have an error. 9:00 And it say's closure use of non-escaping parameter completion. 9:03 It says fix it so we will select that fix solution. 9:07 And what it does is it puts this precompiler directive right here. 9:12 It says @escaping. 9:17 By default with swift too. 9:19 This was the default that you could escape whatever value that you're creating. 9:22 Any local variables that you're creating. 9:27 And if you're passing it to a completion block which means that you're 9:30 escaping out of the local scope that you have defined. 9:34 You need to instruct the compiler that you know what you are doing. 9:39 You're not just passing data around and not thinking about the consequences of it. 9:43 Like yeah, I understand that I am escaping the local scope and 9:49 I'm passing off this data to another execution path. 9:53 That's a load photos async going. 9:57 Now going back to our photo stable view controller, 9:59 we will simply use this new method. 10:03 We'll just create a function here called loadPhotos. 10:05 Since this is a static method that will just say loadPhotosAsync. 10:13 And then it's being passed to us so we'll say self.photos = photos. 10:19 And back here we will not, 10:25 we'll just delete this because we're not going to synchronously load the photos. 10:28 Of course, now that we have loaded the photos, we want to reload our table view. 10:34 We'll say self.tableView. 10:40 Oops. 10:42 ReloadData. 10:45 One thing, of course, is your meaning is we have to call this load photos method. 10:48 We'll do that upon viewDidLoad, 10:53 the super viewDidLoad we will call load photos. 10:57 Once this view is loaded. 11:03 We will load all the photos. 11:06 Let's run our app and see if this has made any kind of difference at all. 11:08 Now, right away you can see the table view and you can also interact with the UI, 11:15 so, we're not just seeing a blank screen and the user to not interact with it. 11:21 The problem with a blank screen that the user cannot interact with 11:26 is that the user things that your app has hung. 11:30 Of course, we can show a little loading indicator which might be helpful but 11:33 I will leave that as a bonus exercise for you, and 11:38 the other thing that I wanna show you, let's create a break point here. 11:41 When we call the URL session, of course it's still in the main queue, but once 11:49 you're inside the URL session, so we'll just run this to the next break point. 11:53 Here you can see that it is in the background queue. 12:00 You know it just say it is in this operation queue. 12:04 It's not the main que anymore. 12:07 It's not Thread 1 com.apple.main-thread. 12:09 It's not doing that anymore. 12:12 It's doing it in the background queue. 12:13 That's why I UI is not being blocked anymore and 12:17 our app is a bit more responsive. 12:20 Of course we're certainly not out of the weeds yet 12:22 because we have a scrolling issue that still needs to be addressed. 12:25 In our next video we will address the scrolling issue. 12:29 And we will dive into the basics of Grand Central Dispatch. 12:32
You need to sign up for Treehouse in order to download course files.Sign up