0 1 00:00:00,530 --> 00:00:05,220 Now, those of you guys who are looking closely, you might have noticed that in the last lesson, we've ran 1 2 00:00:05,390 --> 00:00:12,540 our app and tested whether if our checking and unchecking was persisted into our plist, as soon as we checked 2 3 00:00:12,540 --> 00:00:17,520 off the first item, the last two items in our item.plist got erased. 3 4 00:00:17,520 --> 00:00:23,670 And the reason for that is because we're calling save items when we toggle the check box and that will 4 5 00:00:23,760 --> 00:00:26,830 overwrite the current Item.plist file. 5 6 00:00:26,880 --> 00:00:29,220 So let's go ahead and add it back in. 6 7 00:00:29,220 --> 00:00:31,490 So why does our app do that? 7 8 00:00:32,430 --> 00:00:38,410 Well, the problem is that we're not yet loading up our data from our Items.plist, 8 9 00:00:38,640 --> 00:00:46,410 instead we're loading it up by hardcoding the items and appending them to this itemArray which we 9 10 00:00:46,410 --> 00:00:48,200 know does not get persisted. 10 11 00:00:48,360 --> 00:00:54,050 So whereas, previously, we loaded our items from the UserDefault by using these lines, 11 12 00:00:54,140 --> 00:01:02,090 now we've commented out, and so we have to replace it with some more code that loads up our 12 13 00:01:02,130 --> 00:01:02,540 Item.plist. 13 14 00:01:02,550 --> 00:01:09,840 So instead of writing our code here, I'm just going to call a method called loadItems and it doesn't 14 15 00:01:09,840 --> 00:01:10,710 exist yet, 15 16 00:01:10,710 --> 00:01:16,230 so Xcode is going to complain. But not for long because I'm going to create the function here and 16 17 00:01:16,230 --> 00:01:20,060 I'm going to call it loadItems, just as I called it above. 17 18 00:01:20,130 --> 00:01:26,340 And inside here, we're going to tap into our data by creating a constant and we're going to set it to 18 19 00:01:26,400 --> 00:01:33,950 equal data created using the contents of a URL, 19 20 00:01:34,260 --> 00:01:41,070 so this method. Hit enter. And the URL is, of course, still going to be our dataFilePath. 20 21 00:01:41,370 --> 00:01:44,480 And this is, again, a method that can throw an error. 21 22 00:01:44,550 --> 00:01:52,050 So I'm going to mark it with a "try?" which will turn the result of this method into an 22 23 00:01:52,050 --> 00:01:52,820 optional. 23 24 00:01:52,890 --> 00:01:57,820 So then I'm going to use optional binding to unwrap that safely. 24 25 00:01:57,870 --> 00:02:04,830 So, now just as above we created an object that was an encoder using the PropertyListEncoder in order 25 26 00:02:04,830 --> 00:02:06,550 to decode our items. 26 27 00:02:06,630 --> 00:02:12,540 We have to create a decoder, and you guessed it, it's a PropertyListDecoder. 27 28 00:02:12,780 --> 00:02:18,890 So let's hit enter. And we're going to create a new object of that class. Once we've got our decoder, 28 29 00:02:18,900 --> 00:02:21,760 we're going to set our array up here, 29 30 00:02:21,780 --> 00:02:24,750 itemArray, which contains an array of items. 30 31 00:02:24,840 --> 00:02:30,780 So itemArray is now going to be equal to 31 32 00:02:30,980 --> 00:02:32,520 decoder.decode. 32 33 00:02:32,580 --> 00:02:38,540 So this is the method that's going to decode our data from the dataFilePath. 33 34 00:02:38,760 --> 00:02:45,180 But we have to specify what is the data type of the thing that's going to be decoded because Swift isn't 34 35 00:02:45,180 --> 00:02:47,750 able to reliably infer the data type. 35 36 00:02:47,760 --> 00:02:52,390 And this is one of those rare cases where you actually have to tell it what is the data type. 36 37 00:02:52,410 --> 00:02:56,460 So the data type is, of course, an array of items. 37 38 00:02:56,460 --> 00:03:02,370 And because we're not specifying object, in order to refer to the type that is array of items, we actually 38 39 00:03:02,400 --> 00:03:04,930 also have to write .self here. 39 40 00:03:05,250 --> 00:03:12,090 And the Data is, of course, that data that we safely unwrapped above. And this method, again, needs a "try" 40 41 00:03:12,090 --> 00:03:13,400 keyword in front of it. 41 42 00:03:13,590 --> 00:03:23,720 So we're going to wrap this inside a do block and we're going to catch the errors by printing out. 42 43 00:03:23,720 --> 00:03:30,110 Now, let's just make sure that we called loadItems correctly inside viewDidLoad and we can safely 43 44 00:03:30,110 --> 00:03:38,630 delete all of this hardcoded item initialization, because as we can see, we've already successfully saved 44 45 00:03:38,960 --> 00:03:42,430 all of those items into our Item.plist, 45 46 00:03:42,440 --> 00:03:45,350 so we don't need to initialize it all over again. 46 47 00:03:45,350 --> 00:03:50,480 Now, before we run our app, there's one last thing that we need to do with decoding that we did with 47 48 00:03:50,570 --> 00:03:51,730 encoding. 48 49 00:03:51,830 --> 00:04:02,040 We need to say that our Item class is not only encodedable, but it's also conforming to the decodable protocol. 49 50 00:04:02,060 --> 00:04:10,250 This is a type that only contains standard data types and it can be decoded from another representation 50 51 00:04:10,340 --> 00:04:11,920 which in our case is a plist. 51 52 00:04:11,930 --> 00:04:17,300 Now, it's a little bit silly having encodable and decodable. And since Swift 4, you can replace it with 52 53 00:04:17,300 --> 00:04:23,360 just the word "Codable." And this specifies that a particular class and all of their objects conform to 53 54 00:04:23,360 --> 00:04:26,780 both the encodable and the decodable protocols. 54 55 00:04:26,780 --> 00:04:34,960 So let's hit save and let's check that we've called loadItems in vieDidLoad, and let's run our app. 55 56 00:04:35,000 --> 00:04:35,600 Cool. 56 57 00:04:35,600 --> 00:04:44,210 So we've now managed to successfully load up all of the items that currently exist in our Items.plist, 57 58 00:04:44,540 --> 00:04:50,330 and you can see that if I check on one of these items, that the done property updates live. 58 59 00:04:53,240 --> 00:04:54,170 Cool, right? 59 60 00:04:54,170 --> 00:05:01,130 So we've now managed to successfully do what we weren't able to do before which is save an array of 60 61 00:05:01,160 --> 00:05:06,760 custom objects into persisted storage and retrieve it at a later date. 61 62 00:05:06,890 --> 00:05:14,240 So, now if I go ahead and terminate this app, if I open it again, all my checkmarks still exist in the 62 63 00:05:14,240 --> 00:05:18,230 right places and all my items still get loaded up. 63 64 00:05:18,230 --> 00:05:26,420 So in this lesson, we use the NSCoder in order to encode and decode our data to a prespecified file path, 64 65 00:05:26,570 --> 00:05:35,390 and our code converted our array of items into a plist file which we can then save and retrieve from. 65 66 00:05:35,720 --> 00:05:40,160 Now, does encoding and decoding makes sense to you? 66 67 00:05:40,260 --> 00:05:41,220 Not yet? 67 68 00:05:41,350 --> 00:05:44,260 All right, let's think about it from a different perspective. 68 69 00:05:44,490 --> 00:05:50,550 When you encode data, you're essentially converting one data type into another. 69 70 00:05:50,550 --> 00:05:56,770 It's almost the same as converting your music into a vinyl disc. 70 71 00:05:56,790 --> 00:06:04,740 And what this machine does is that it takes music and it etches into a vinyl disc all the grooves that 71 72 00:06:04,740 --> 00:06:06,970 correspond to the music. 72 73 00:06:07,230 --> 00:06:18,970 So we're using the encoder to turn music into a vinyl disc, and that is our encoder. Now, our decoder takes 73 74 00:06:18,970 --> 00:06:26,590 that same vinyl disc and plays it or turns it back into the music. 74 75 00:06:26,690 --> 00:06:29,920 And this is exactly the same as what we're doing here. 75 76 00:06:30,320 --> 00:06:33,090 We're encoding one type of data, 76 77 00:06:33,170 --> 00:06:40,310 our array of custom objects into data that can be written into a plist, and then when we need that data, 77 78 00:06:40,640 --> 00:06:48,490 we use a plist decoder to take out that data in the form of an array of items. 78 79 00:06:48,500 --> 00:06:55,790 So this gives us way more flexibility over our NSUserDefaults. And when we save data to our 79 80 00:06:55,790 --> 00:06:56,720 NSUserDefaults, 80 81 00:06:56,720 --> 00:07:03,610 they all went into the same plist. But in our case, we can actually initialize different plists. 81 82 00:07:03,650 --> 00:07:09,620 For example, if we had different categories to our to-do list, we had one to-do list that was for home, 82 83 00:07:09,700 --> 00:07:11,500 one to-do list that was for work, 83 84 00:07:11,780 --> 00:07:18,170 instead of loading up a large plist that contains all of our items, we could actually separate it out 84 85 00:07:18,260 --> 00:07:21,810 into individual plist for each and every category, 85 86 00:07:21,890 --> 00:07:26,780 reducing the loading time every time we want to read and write to that plist. 86 87 00:07:26,810 --> 00:07:32,090 So have a play around with the code. And in the next lesson, we're going to make our persistent storage 87 88 00:07:32,450 --> 00:07:37,550 even more flexible and even more scalable by using Core Data. 88 89 00:07:37,570 --> 00:07:38,480 So I'll see you there.