diff --git a/subtitles/en/Lecture 10. Navigation + TextField b/subtitles/en/Lecture 10. Navigation + TextField new file mode 100644 index 0000000..649e7a8 --- /dev/null +++ b/subtitles/en/Lecture 10. Navigation + TextField @@ -0,0 +1,9632 @@ +1 +00:00:00,167 --> 00:00:03,000 +(celestial music) + +2 +00:00:04,920 --> 00:00:06,523 +- [Narrator] Stanford University. + +3 +00:00:08,610 --> 00:00:13,280 +- [Presenter] Lecture 10 of +Stanford CS193p spring of 2020 + +4 +00:00:13,280 --> 00:00:17,470 +is all about demo, all +demo all the time today. + +5 +00:00:17,470 --> 00:00:22,200 +This demo is mostly about +presenting Views on screen. + +6 +00:00:22,200 --> 00:00:24,790 +We already know how to do that somewhat. + +7 +00:00:24,790 --> 00:00:28,560 +ForEach's will bring Views +on screen and off screen. + +8 +00:00:28,560 --> 00:00:31,150 +Also, if-elses inside of ViewBuilders, + +9 +00:00:31,150 --> 00:00:33,400 +those make Views come and go. + +10 +00:00:33,400 --> 00:00:36,350 +But now we're talking about +large groupings of Views, + +11 +00:00:36,350 --> 00:00:39,400 +Views that might take +over the entire screen, + +12 +00:00:39,400 --> 00:00:43,300 +Views that might be driven +by their own MVVMs, right? + +13 +00:00:43,300 --> 00:00:46,460 +Having their own ViewModels, +which we have not seen + +14 +00:00:46,460 --> 00:00:49,787 +an app yet that has multiple ViewModels, + +15 +00:00:49,787 --> 00:00:51,040 +but we're gonna see that today. + +16 +00:00:51,040 --> 00:00:52,853 +We're gonna take Emoji +Art to the next level. + +17 +00:00:52,853 --> 00:00:55,440 +It's gonna have multiple ViewModels. + +18 +00:00:55,440 --> 00:00:59,940 +And of course, most large +programs have many ViewModels. + +19 +00:00:59,940 --> 00:01:03,260 +As usual these things that +I'm showing you in the demo + +20 +00:01:03,260 --> 00:01:05,150 +are just intended to introduce + +21 +00:01:05,150 --> 00:01:08,100 +this functionality to you in context. + +22 +00:01:08,100 --> 00:01:10,270 +That's why we do Memorize and Emoji Art + +23 +00:01:10,270 --> 00:01:11,690 +so you have a context + +24 +00:01:11,690 --> 00:01:14,610 +to see this functionality +introduced to you. + +25 +00:01:14,610 --> 00:01:17,860 +Still no substitute from +going to the documentation, + +26 +00:01:17,860 --> 00:01:20,250 +reading about things, +try to understand them. + +27 +00:01:20,250 --> 00:01:22,150 +That's a lot of why we ask +you to do the homework, + +28 +00:01:22,150 --> 00:01:25,543 +so you have to really figure +out how to use these things. + +29 +00:01:26,650 --> 00:01:28,450 +Here's a list of what +we're gonna do today. + +30 +00:01:28,450 --> 00:01:30,580 +I'm not gonna go over this, +but just for quick reference, + +31 +00:01:30,580 --> 00:01:31,807 +you can always go back and say, + +32 +00:01:31,807 --> 00:01:33,980 +"What was I supposed to +have learned in this demo?" + +33 +00:01:33,980 --> 00:01:35,767 +It's a very long list as you can see, + +34 +00:01:35,767 --> 00:01:39,113 +and a lot of very important +things in this list as well. + +35 +00:01:40,110 --> 00:01:42,573 +So without further ado, let's get started. + +36 +00:01:43,560 --> 00:01:47,760 +This demo is gonna be all +about putting Views on screen + +37 +00:01:47,760 --> 00:01:50,850 +in different ways, Alerts, +popovers, et cetera. + +38 +00:01:50,850 --> 00:01:53,370 +But before I dive into +that, I want to show you + +39 +00:01:53,370 --> 00:01:56,920 +one little thing that we +could have done last time + +40 +00:01:56,920 --> 00:01:59,820 +that I think is worth showing, +just so you understand + +41 +00:01:59,820 --> 00:02:02,860 +these property wrappers +a little bit better. + +42 +00:02:02,860 --> 00:02:05,840 +Now, you remember that +we wanted to initialize + +43 +00:02:05,840 --> 00:02:09,720 +this chosen palette using our +document's default palette. + +44 +00:02:09,720 --> 00:02:13,890 +But we couldn't do that here +because this ObservedObject + +45 +00:02:13,890 --> 00:02:15,570 +is part of what's being initialized, + +46 +00:02:15,570 --> 00:02:19,710 +and so we can't during +initialize do it here. + +47 +00:02:19,710 --> 00:02:23,120 +Now, it turns out we can't +really do it in an init either. + +48 +00:02:23,120 --> 00:02:26,633 +So if we had an init +that took the document, + +49 +00:02:27,965 --> 00:02:32,910 +and just said self.document, +equals that document, + +50 +00:02:32,910 --> 00:02:37,093 +then unfortunately, we can't +even do this right here. + +51 +00:02:38,150 --> 00:02:39,980 +You'd think maybe we could do that + +52 +00:02:39,980 --> 00:02:41,720 +because now we have the document, + +53 +00:02:41,720 --> 00:02:43,977 +we can just set our chosen palette. + +54 +00:02:43,977 --> 00:02:47,250 +But the thing is here we are +in the middle of initializing + +55 +00:02:47,250 --> 00:02:50,130 +and this needs to be initialized. + +56 +00:02:50,130 --> 00:02:52,320 +I'm kinda surprised this even compiles + +57 +00:02:52,320 --> 00:02:54,010 +although, I could imagine a cool feature + +58 +00:02:54,010 --> 00:02:57,900 +where this would compile and +actually work, but it doesn't. + +59 +00:02:57,900 --> 00:03:00,130 +What we have to do +instead here in our init + +60 +00:03:00,130 --> 00:03:02,660 +is initialize the actual variable + +61 +00:03:02,660 --> 00:03:04,750 +being created by this State, + +62 +00:03:04,750 --> 00:03:07,070 +which if you'll remember +what that variable is + +63 +00:03:07,070 --> 00:03:10,230 +its _chosenPalette. + +64 +00:03:10,230 --> 00:03:13,550 +And this _chosenPalette is of type State. + +65 +00:03:13,550 --> 00:03:14,970 +It is the State struct. + +66 +00:03:14,970 --> 00:03:17,980 +That's what this line of +code actually creates. + +67 +00:03:17,980 --> 00:03:21,070 +So we can initialize +it by creating a State. + +68 +00:03:21,070 --> 00:03:23,150 +And in fact, we're gonna create a State + +69 +00:03:23,150 --> 00:03:26,410 +that whose wrappedValue +is the value we want. + +70 +00:03:26,410 --> 00:03:28,673 +So this document's default palette. + +71 +00:03:29,640 --> 00:03:33,520 +This is a way to initialize +your State in your initializers + +72 +00:03:33,520 --> 00:03:36,850 +by setting this struct directly. + +73 +00:03:36,850 --> 00:03:39,110 +Hopefully, you don't have +to do this very often. + +74 +00:03:39,110 --> 00:03:41,700 +And I'm imagining this is +gonna be more elegant ways + +75 +00:03:41,700 --> 00:03:43,550 +to do it in the future of Swift, + +76 +00:03:43,550 --> 00:03:47,420 +but this really does show +you what this is creating, + +77 +00:03:47,420 --> 00:03:50,890 +it's creating this underbar +var which is one of these. + +78 +00:03:50,890 --> 00:03:52,690 +So we don't really need our onAppear. + +79 +00:03:52,690 --> 00:03:54,490 +Our onAppear worked fine there actually + +80 +00:03:54,490 --> 00:03:56,840 +but this is more of a, kind +of an educational thing + +81 +00:03:56,840 --> 00:03:59,370 +about what's going on with +these property wrappers. + +82 +00:03:59,370 --> 00:04:01,220 +And later in the quarter, +I hope to actually, + +83 +00:04:01,220 --> 00:04:03,290 +maybe we'll create our +own property wrapper, + +84 +00:04:03,290 --> 00:04:05,840 +and then we'll really +understand these things. + +85 +00:04:05,840 --> 00:04:07,187 +But in the meantime, this should help you + +86 +00:04:07,187 --> 00:04:09,113 +understand it a little better. + +87 +00:04:11,060 --> 00:04:15,810 +Let's dive in now to what we +actually want to build which is + +88 +00:04:17,500 --> 00:04:19,430 +a palette editor. + +89 +00:04:19,430 --> 00:04:21,930 +So right now I've got +these palettes right here, + +90 +00:04:21,930 --> 00:04:24,710 +and I can choose between +them, but I can't change them, + +91 +00:04:24,710 --> 00:04:27,720 +can't add emoji here, can't remove emoji, + +92 +00:04:27,720 --> 00:04:30,610 +can't change the name of this faces thing. + +93 +00:04:30,610 --> 00:04:32,090 +So I wanna be able to do that, + +94 +00:04:32,090 --> 00:04:33,890 +I wanna be able to edit them. + +95 +00:04:33,890 --> 00:04:37,570 +And I'm gonna do that by +providing a little icon right here + +96 +00:04:37,570 --> 00:04:40,057 +next to the name of the palette. + +97 +00:04:40,057 --> 00:04:42,220 +And when you touch on that icon, + +98 +00:04:42,220 --> 00:04:43,360 +it's gonna bring up some UI + +99 +00:04:43,360 --> 00:04:45,810 +that lets you add and remove emojis, + +100 +00:04:45,810 --> 00:04:47,310 +change the name, et cetera. + +101 +00:04:47,310 --> 00:04:49,273 +Essentially a palette editor. + +102 +00:04:50,170 --> 00:04:53,140 +Let's get started by +putting a little icon here. + +103 +00:04:53,140 --> 00:04:56,830 +Now, I went into SF Symbols over here + +104 +00:04:56,830 --> 00:04:58,760 +and I looked around trying to decide + +105 +00:04:58,760 --> 00:05:00,140 +what would be a good icon here + +106 +00:05:00,140 --> 00:05:01,400 +that would help people understand + +107 +00:05:01,400 --> 00:05:03,800 +what touching on it would do? + +108 +00:05:03,800 --> 00:05:07,010 +And I kind of landed on a keyboard, + +109 +00:05:07,010 --> 00:05:08,440 +because most of what +they're gonna be doing + +110 +00:05:08,440 --> 00:05:12,480 +is using a keyboard, Emoji +Keyboard to add more emoji here. + +111 +00:05:12,480 --> 00:05:14,330 +So I thought that might be good. + +112 +00:05:14,330 --> 00:05:16,150 +You know, when I get into user testing + +113 +00:05:16,150 --> 00:05:18,437 +and doing focus groups, we +find out people are like, + +114 +00:05:18,437 --> 00:05:19,337 +"What's that keyboard? + +115 +00:05:19,337 --> 00:05:20,830 +"I have no idea what that is." + +116 +00:05:20,830 --> 00:05:23,190 +And we might even change +it to something else. + +117 +00:05:23,190 --> 00:05:26,380 +When you're building +a UI, you can't assume + +118 +00:05:26,380 --> 00:05:27,970 +that you're going to see the world + +119 +00:05:27,970 --> 00:05:30,450 +exactly the same way as your users. + +120 +00:05:30,450 --> 00:05:34,590 +So you have to be able to be +adaptable to what your users + +121 +00:05:34,590 --> 00:05:37,700 +actually understand +about how your app works. + +122 +00:05:37,700 --> 00:05:38,533 +But we're gonna start with the keyboard. + +123 +00:05:38,533 --> 00:05:40,723 +So I'm gonna add a little +keyboard right there, + +124 +00:05:40,723 --> 00:05:43,330 +a keyboard image right after the name, + +125 +00:05:43,330 --> 00:05:45,050 +and that's gonna be really easy to do. + +126 +00:05:45,050 --> 00:05:46,060 +Here's where our name is, + +127 +00:05:46,060 --> 00:05:48,357 +here's where that +plus-minus stepper thing is. + +128 +00:05:48,357 --> 00:05:52,970 +I'm just gonna say Image, +systemName, use the keyboard. + +129 +00:05:52,970 --> 00:05:56,410 +Again, this keyboard is something +I looked up in SF Symbols. + +130 +00:05:56,410 --> 00:05:58,210 +And I'm gonna also make it large. + +131 +00:05:58,210 --> 00:06:00,470 +I'm gonna do this imageScale.large + +132 +00:06:03,000 --> 00:06:04,810 +Simple enough to add this little image. + +133 +00:06:04,810 --> 00:06:07,140 +There it is right there, +it's on every one. + +134 +00:06:07,140 --> 00:06:10,340 +And when I touch on this, +I want some UI to come up + +135 +00:06:10,340 --> 00:06:13,813 +that lets me edit this +palette. So how do we do that? + +136 +00:06:13,813 --> 00:06:16,290 +How do we make it so that +touching on something + +137 +00:06:16,290 --> 00:06:19,060 +causes some UI to come up? + +138 +00:06:19,060 --> 00:06:21,060 +I'm gonna use a popover in this case, + +139 +00:06:21,060 --> 00:06:22,650 +we're gonna be showing +lots of different ways + +140 +00:06:22,650 --> 00:06:25,300 +to bring things up, but I'm +gonna do popover to start. + +141 +00:06:25,300 --> 00:06:27,620 +So popover is just like +a little rectangular area + +142 +00:06:27,620 --> 00:06:29,150 +that will appear. + +143 +00:06:29,150 --> 00:06:32,460 +And it'll kind of point to +the thing that brings it up. + +144 +00:06:32,460 --> 00:06:34,690 +So this is gonna be our +little keyboard icon + +145 +00:06:34,690 --> 00:06:35,960 +that brings it up, so it's gonna point + +146 +00:06:35,960 --> 00:06:37,460 +at that little keyboard icon + +147 +00:06:37,460 --> 00:06:40,247 +so that when it's up, +this user can remember, + +148 +00:06:40,247 --> 00:06:42,747 +"Oh, yeah, I clicked on +that little keyboard icon. + +149 +00:06:42,747 --> 00:06:47,480 +"That's how this little +UI, this View came up." + +150 +00:06:47,480 --> 00:06:50,130 +So how do we make a popover appear? + +151 +00:06:50,130 --> 00:06:54,440 +We just go here to the +View we want it to point to + +152 +00:06:54,440 --> 00:06:58,200 +when it comes up, which is +our image and we say popover. + +153 +00:06:58,200 --> 00:07:01,470 +Popover has four different +ways to bring it up, here. + +154 +00:07:01,470 --> 00:07:05,220 +Two of them involved passing +it a Binding to an Identifiable + +155 +00:07:05,220 --> 00:07:07,600 +and that Identifiable is +gonna kind of identify + +156 +00:07:07,600 --> 00:07:09,980 +what thing you wanna show in the popover. + +157 +00:07:09,980 --> 00:07:11,460 +But a lot of times in a popover, + +158 +00:07:11,460 --> 00:07:12,690 +we're showing the same thing. + +159 +00:07:12,690 --> 00:07:15,460 +Like in our case, we always +show a palette editor. + +160 +00:07:15,460 --> 00:07:16,760 +That's all it shows. + +161 +00:07:16,760 --> 00:07:19,440 +So we can use one of +these two popover things: + +162 +00:07:19,440 --> 00:07:21,580 +isPresented's right here. + +163 +00:07:21,580 --> 00:07:25,310 +And these isPresented versions +take a Binding to a Bool, + +164 +00:07:25,310 --> 00:07:27,990 +and that Bool says whether that popover + +165 +00:07:27,990 --> 00:07:29,980 +is currently showing or not. + +166 +00:07:29,980 --> 00:07:31,570 +Let's use this one right here, + +167 +00:07:31,570 --> 00:07:33,810 +we need to give it a Binding to a Bool. + +168 +00:07:33,810 --> 00:07:35,380 +We know how to do Bindings now. + +169 +00:07:35,380 --> 00:07:38,420 +We create our own State. + +170 +00:07:38,420 --> 00:07:40,640 +So I'll make a little private State here. + +171 +00:07:40,640 --> 00:07:42,773 +I'll call it showPaletteEditor. + +172 +00:07:43,720 --> 00:07:45,940 +And it's a Bool, it's +gonna start out false. + +173 +00:07:45,940 --> 00:07:49,010 +In other words, I don't want +the palette editor showing + +174 +00:07:49,010 --> 00:07:50,960 +when my, this View first comes up. + +175 +00:07:50,960 --> 00:07:52,960 +And I just provide a Binding to that + +176 +00:07:52,960 --> 00:07:55,107 +which is $showPaletteEditor. + +177 +00:07:55,990 --> 00:07:59,320 +Remember, dollar on a State is a Binding + +178 +00:07:59,320 --> 00:08:00,950 +to this value of the State. + +179 +00:08:00,950 --> 00:08:03,270 +And this Bool is now gonna be shared + +180 +00:08:03,270 --> 00:08:06,370 +between the popover and us. + +181 +00:08:06,370 --> 00:08:08,110 +Now, who's gonna do what? + +182 +00:08:08,110 --> 00:08:10,440 +Well, I'm going to set this to true + +183 +00:08:10,440 --> 00:08:12,910 +whenever I want this popover to appear. + +184 +00:08:12,910 --> 00:08:14,730 +And when the popover is up, + +185 +00:08:14,730 --> 00:08:17,880 +if the user taps somewhere +else outside the popover, + +186 +00:08:17,880 --> 00:08:21,780 +it's gonna set this back to +false, and then it'll disappear. + +187 +00:08:21,780 --> 00:08:24,040 +So we're going to be talking to each other + +188 +00:08:24,040 --> 00:08:27,453 +through this Bool right +here, this boolean value. + +189 +00:08:28,410 --> 00:08:29,390 +And then the content. + +190 +00:08:29,390 --> 00:08:31,670 +This is just like anything +else that has content here, + +191 +00:08:31,670 --> 00:08:34,130 +we're just providing a View, + +192 +00:08:34,130 --> 00:08:36,390 +it's probably a ViewBuilder, in fact. + +193 +00:08:36,390 --> 00:08:39,740 +And here our View that we wanna present + +194 +00:08:39,740 --> 00:08:41,550 +is our PaletteEditor. + +195 +00:08:42,551 --> 00:08:46,600 +So we're gonna have to create +our own little View here + +196 +00:08:46,600 --> 00:08:50,133 +to edit palette, let's +do that, easy to do. + +197 +00:08:50,133 --> 00:08:51,943 +Make some space down here. + +198 +00:08:53,490 --> 00:08:56,020 +And we'll say struct PaletteEditor. + +199 +00:08:56,930 --> 00:09:01,287 +It's a View that means it has +var body, which some View. + +200 +00:09:01,287 --> 00:09:04,327 +And for now I'm just gonna +have it be a Text that says + +201 +00:09:04,327 --> 00:09:08,343 +"Palette Editor," because +that's what this thing is. + +202 +00:09:09,400 --> 00:09:11,710 +Now, you might think, "Okay, we got it." + +203 +00:09:11,710 --> 00:09:13,970 +Popover, yep, let's do it, let's run, + +204 +00:09:13,970 --> 00:09:18,970 +we should be able to tap on +our image somehow and see this. + +205 +00:09:21,090 --> 00:09:23,240 +Here we go, tap. + +206 +00:09:23,240 --> 00:09:26,513 +Oh, I don't see any change, tap, tap, tap. + +207 +00:09:27,510 --> 00:09:31,240 +That's because we never set +this showPaletteEditor Bool + +208 +00:09:32,570 --> 00:09:34,080 +to true, it's always false. + +209 +00:09:34,080 --> 00:09:37,100 +So that means that popover +is always never showing. + +210 +00:09:37,100 --> 00:09:39,310 +So the popover's doing +exactly the right thing. + +211 +00:09:39,310 --> 00:09:41,240 +Remember, this is declarative UI, + +212 +00:09:41,240 --> 00:09:44,140 +we're just declaring that +a popover should appear, + +213 +00:09:44,140 --> 00:09:46,810 +this should appear in a +popover when this is true, + +214 +00:09:46,810 --> 00:09:48,543 +but we never set this to true. + +215 +00:09:49,410 --> 00:09:50,790 +That's easily enough done though. + +216 +00:09:50,790 --> 00:09:53,710 +OnTapGesture of this Image, + +217 +00:09:53,710 --> 00:09:57,190 +self.showPalettEditor equals true. + +218 +00:09:57,190 --> 00:09:59,300 +So when you tap on this +keyboard right here, + +219 +00:09:59,300 --> 00:10:01,540 +I'm going to set that to true. + +220 +00:10:01,540 --> 00:10:04,480 +And we declared that this +popover should appear + +221 +00:10:04,480 --> 00:10:06,353 +when that happens, see this work. + +222 +00:10:09,143 --> 00:10:10,669 +Here we go, ready? + +223 +00:10:10,669 --> 00:10:13,220 +Beep, there it is our palette editor. + +224 +00:10:13,220 --> 00:10:15,220 +So I tapped on that, I set it to be true + +225 +00:10:15,220 --> 00:10:17,960 +and so that popover is declared to show + +226 +00:10:17,960 --> 00:10:18,930 +when that thing is true. + +227 +00:10:18,930 --> 00:10:22,750 +And similarly, when I click +anywhere else outside of there, + +228 +00:10:22,750 --> 00:10:26,520 +boop, the popover sets that +variable back to false. + +229 +00:10:26,520 --> 00:10:30,240 +So that's how we're again +communicating with each other. + +230 +00:10:30,240 --> 00:10:33,790 +And see the little triangle +at the top of the popover + +231 +00:10:33,790 --> 00:10:36,530 +that is showing the user +what they touched on + +232 +00:10:36,530 --> 00:10:38,940 +to cause this popover to appear, + +233 +00:10:38,940 --> 00:10:43,340 +and you can set the allowed +directions of that arrow + +234 +00:10:43,340 --> 00:10:45,230 +and that somewhat controls + +235 +00:10:45,230 --> 00:10:47,830 +where your popover is allowed to come up. + +236 +00:10:47,830 --> 00:10:50,160 +The system is gonna +try and fit the popover + +237 +00:10:50,160 --> 00:10:53,130 +and obey the arrow +directions that you want. + +238 +00:10:53,130 --> 00:10:56,380 +By the way, popovers are +pretty much an iPad thing + +239 +00:10:56,380 --> 00:10:59,810 +because there's really not +a lot of room on an iPhone, + +240 +00:10:59,810 --> 00:11:02,130 +but we're gonna see that the iPhone adapts + +241 +00:11:02,130 --> 00:11:04,420 +and still can show a popover, + +242 +00:11:04,420 --> 00:11:05,693 +but it doesn't show it as a popover, + +243 +00:11:05,693 --> 00:11:07,760 +it just uses full screen. + +244 +00:11:07,760 --> 00:11:09,310 +We'll see that in a little bit. + +245 +00:11:10,720 --> 00:11:12,450 +Okay, so now we should be able to edit + +246 +00:11:12,450 --> 00:11:15,440 +any of these palettes that we want. + +247 +00:11:15,440 --> 00:11:17,820 +Before we get any farther here, though, + +248 +00:11:17,820 --> 00:11:20,360 +I wanna make this popover +quite a bit bigger. + +249 +00:11:20,360 --> 00:11:21,230 +You can see it's small, + +250 +00:11:21,230 --> 00:11:23,940 +it's sizing itself to fit our content, + +251 +00:11:23,940 --> 00:11:27,077 +which is actually good, that's +a cool feature of popover. + +252 +00:11:27,077 --> 00:11:28,530 +And we could put some padding around here. + +253 +00:11:28,530 --> 00:11:30,210 +But instead of just putting padding, + +254 +00:11:30,210 --> 00:11:31,360 +I wanna make some space. + +255 +00:11:31,360 --> 00:11:34,050 +So as I build my UI, you're +gonna get a better idea + +256 +00:11:34,050 --> 00:11:36,840 +what it's eventually going to look like. + +257 +00:11:36,840 --> 00:11:39,840 +Making space, making this larger, + +258 +00:11:39,840 --> 00:11:40,913 +we could again try and do it + +259 +00:11:40,913 --> 00:11:42,680 +if I just put some padding around it, + +260 +00:11:42,680 --> 00:11:44,410 +that would make it a little bit bigger. + +261 +00:11:44,410 --> 00:11:48,070 +But instead I'm going to make +the entire Palette Editor + +262 +00:11:48,070 --> 00:11:50,340 +have a minimum size. + +263 +00:11:50,340 --> 00:11:53,360 +We do that with .frame, +we've seen .frame before. + +264 +00:11:53,360 --> 00:11:54,747 +And as I told you before, + +265 +00:11:54,747 --> 00:11:56,627 +.frame has a lot of arguments down here + +266 +00:11:56,627 --> 00:12:00,400 +and we're gonna use the minWidth +and minHeight arguments. + +267 +00:12:00,400 --> 00:12:03,740 +So here's minWidth, maybe 300 wide, + +268 +00:12:03,740 --> 00:12:08,063 +and minHeight, something like 500. + +269 +00:12:09,230 --> 00:12:13,200 +That looks like touch, +all right, much better! + +270 +00:12:13,200 --> 00:12:15,780 +So we got plenty of room +to maneuver in here. + +271 +00:12:15,780 --> 00:12:19,350 +Might be down the road, once +I get this UI the way I want, + +272 +00:12:19,350 --> 00:12:21,590 +I won't require to have a minWidth. + +273 +00:12:21,590 --> 00:12:23,420 +But I could always leave +it in there as well, + +274 +00:12:23,420 --> 00:12:25,763 +depends on what I want my UI to look like. + +275 +00:12:26,920 --> 00:12:29,280 +We wanna be able to edit this palette, + +276 +00:12:29,280 --> 00:12:33,210 +so let's make sure we +can transfer this palette + +277 +00:12:33,210 --> 00:12:35,563 +into this editor so that it can edit it. + +278 +00:12:37,970 --> 00:12:40,830 +So to do that, I'm gonna +have my text: Palette Editor. + +279 +00:12:40,830 --> 00:12:42,990 +I'm gonna put a little Divider, + +280 +00:12:42,990 --> 00:12:46,683 +and now I'm gonna put +Text of my chosenPalette. + +281 +00:12:47,810 --> 00:12:49,730 +I want this chosenPalette right here + +282 +00:12:49,730 --> 00:12:52,930 +to be the same as this +chosenPalette up here. + +283 +00:12:52,930 --> 00:12:55,030 +So we're gonna edit whatever chosenPalette + +284 +00:12:55,030 --> 00:12:56,410 +we're showing here. + +285 +00:12:56,410 --> 00:12:59,140 +To do that, I'm just +gonna create a Binding + +286 +00:13:00,070 --> 00:13:02,260 +to chosenPalette. + +287 +00:13:02,260 --> 00:13:05,080 +Notice I'm giving this +the exact same name, + +288 +00:13:05,080 --> 00:13:07,430 +as I give it in here, +which is even the same name + +289 +00:13:07,430 --> 00:13:08,970 +that we give it over here. + +290 +00:13:08,970 --> 00:13:10,640 +But there's no rule, no law + +291 +00:13:10,640 --> 00:13:12,180 +that says this has to have the same name. + +292 +00:13:12,180 --> 00:13:15,410 +We could call this palette +we're editing if we wanted, + +293 +00:13:15,410 --> 00:13:18,040 +something like that, but +often we'll name them the same + +294 +00:13:18,040 --> 00:13:19,790 +just so people don't get quite confused + +295 +00:13:19,790 --> 00:13:22,810 +because we are Binding them +directly to each other. + +296 +00:13:22,810 --> 00:13:25,743 +So they are essentially +all the same thing. + +297 +00:13:27,320 --> 00:13:30,010 +And so, we can use this +chosenPalette down here. + +298 +00:13:30,010 --> 00:13:32,243 +Let's put these things into a VStack. + +299 +00:13:36,790 --> 00:13:38,767 +And we're seeing that +we have an error here, + +300 +00:13:38,767 --> 00:13:41,660 +"Missing argument for +parameter chosenPalette." + +301 +00:13:41,660 --> 00:13:44,710 +This is an uninitialized +variable in our PaletteEditor. + +302 +00:13:44,710 --> 00:13:47,393 +So we have to initialize +it: chosenPalette. + +303 +00:13:48,924 --> 00:13:52,475 +And how do we give a Binding +to our chosenPalette, + +304 +00:13:52,475 --> 00:13:54,920 +$chosenPalette. + +305 +00:13:54,920 --> 00:13:58,510 +And this chosenPalette in here +is actually a Binding itself. + +306 +00:13:58,510 --> 00:14:00,910 +It's Binding to this State over here, + +307 +00:14:00,910 --> 00:14:03,233 +our document View, this @State. + +308 +00:14:04,070 --> 00:14:07,310 +But we know that if we +do dollar on a Binding, + +309 +00:14:07,310 --> 00:14:10,770 +that that is essentially +returning self, okay, + +310 +00:14:10,770 --> 00:14:13,480 +the Binding itself or +a Binding to the thing + +311 +00:14:13,480 --> 00:14:16,500 +that Binding is binding to either way. + +312 +00:14:16,500 --> 00:14:17,800 +And that's exactly what we want here. + +313 +00:14:17,800 --> 00:14:19,270 +So we want this Binding and that State. + +314 +00:14:19,270 --> 00:14:24,270 +So now there are three Views +all sharing this same value. + +315 +00:14:24,380 --> 00:14:26,750 +Let's make sure this is actually working. + +316 +00:14:27,943 --> 00:14:30,860 +And I'm gonna touch on this keyboard. + +317 +00:14:30,860 --> 00:14:31,777 +Whoa! There it is. + +318 +00:14:31,777 --> 00:14:33,700 +And it is showing this one right here. + +319 +00:14:33,700 --> 00:14:36,450 +Let's go to a different +one and touch on it, + +320 +00:14:36,450 --> 00:14:37,810 +whoa, it's showing it. + +321 +00:14:37,810 --> 00:14:41,690 +So our Palette Editor definitely +got a hold of the palette + +322 +00:14:41,690 --> 00:14:43,963 +that it's supposed to be editing here. + +323 +00:14:45,120 --> 00:14:48,000 +I'm gonna work a little +bit on layout of this. + +324 +00:14:48,000 --> 00:14:50,100 +I want this thing that +says, "Palette Editor" + +325 +00:14:50,100 --> 00:14:51,910 +to really be like at the top + +326 +00:14:51,910 --> 00:14:56,720 +like it's some sort of title +or something to my little View + +327 +00:14:56,720 --> 00:14:58,620 +instead of having it in +the middle like this. + +328 +00:14:58,620 --> 00:15:01,493 +So let's do that layout really quickly. + +329 +00:15:03,008 --> 00:15:06,230 +I'm gonna make this title have more of a + +330 +00:15:06,230 --> 00:15:08,860 +title kind of a font headline. + +331 +00:15:08,860 --> 00:15:11,620 +And I'll give it some padding around it. + +332 +00:15:11,620 --> 00:15:13,620 +And then, let's make it go to the top + +333 +00:15:13,620 --> 00:15:15,720 +by putting a Spacer at the bottom + +334 +00:15:15,720 --> 00:15:18,250 +that just puts a whole +bunch of space in there. + +335 +00:15:18,250 --> 00:15:20,233 +And let's see what that looks like. + +336 +00:15:24,084 --> 00:15:25,580 +Look, getting close. + +337 +00:15:25,580 --> 00:15:27,650 +A little too much spacing in here, + +338 +00:15:27,650 --> 00:15:29,210 +we got the padding around this + +339 +00:15:29,210 --> 00:15:32,360 +and then we've got the spacing +of the VStack it looks like, + +340 +00:15:32,360 --> 00:15:34,050 +so we can get rid of that. + +341 +00:15:38,487 --> 00:15:40,040 +But if I'm doing no spacing, + +342 +00:15:40,040 --> 00:15:43,983 +maybe I want this thing to +have some padding of its own. + +343 +00:15:49,374 --> 00:15:51,960 +All right, that is looking pretty awesome. + +344 +00:15:51,960 --> 00:15:53,310 +We got our palette editor. + +345 +00:15:53,310 --> 00:15:55,650 +This is now the part that is going to be + +346 +00:15:55,650 --> 00:15:56,773 +editing the palette. + +347 +00:15:57,930 --> 00:16:01,520 +Let's start by working on +editing the name of the palette. + +348 +00:16:01,520 --> 00:16:02,840 +So right now we're seeing the palette + +349 +00:16:02,840 --> 00:16:04,860 +but I actually wanna see its name here. + +350 +00:16:04,860 --> 00:16:06,740 +And then we're going to make it editable + +351 +00:16:06,740 --> 00:16:08,770 +so that you can change +this from activities + +352 +00:16:08,770 --> 00:16:11,030 +to something else if you wanted. + +353 +00:16:11,030 --> 00:16:12,940 +So how are we going to do that? + +354 +00:16:12,940 --> 00:16:14,560 +Well, instead of showing the palette, + +355 +00:16:14,560 --> 00:16:15,900 +I wanna show its name. + +356 +00:16:15,900 --> 00:16:17,760 +We do that all over the place up here. + +357 +00:16:17,760 --> 00:16:20,700 +That's this document +paletteNames right here. + +358 +00:16:20,700 --> 00:16:24,307 +I'm gonna copy that code +even and put it down here. + +359 +00:16:24,307 --> 00:16:28,310 +The problem is, we don't have +the document down here, right? + +360 +00:16:28,310 --> 00:16:32,210 +We have the document up +here, but not down here. + +361 +00:16:32,210 --> 00:16:34,717 +You might, your first +inclination might be, + +362 +00:16:34,717 --> 00:16:36,557 +"Oh, let's create another Binding + +363 +00:16:36,557 --> 00:16:39,010 +"and we'll bind up to here." + +364 +00:16:39,010 --> 00:16:42,410 +But that is not how we share ViewModels. + +365 +00:16:42,410 --> 00:16:44,527 +This document is our ViewModel. + +366 +00:16:44,527 --> 00:16:48,823 +And instead we're gonna share +it using EnvironmentObject. + +367 +00:16:51,392 --> 00:16:54,500 +So our document is going +to be an EnvironmentObject. + +368 +00:16:54,500 --> 00:16:57,240 +And we're gonna do it this +way with EnvironmentObject + +369 +00:16:57,240 --> 00:17:00,760 +because we're presenting this +thing in a separate View. + +370 +00:17:00,760 --> 00:17:03,260 +Anytime we're gonna present +something in a popover, + +371 +00:17:03,260 --> 00:17:05,030 +or any kinda separate View, + +372 +00:17:05,030 --> 00:17:09,730 +we want to pass our ViewModel +using EnvironmentObject. + +373 +00:17:09,730 --> 00:17:12,000 +And we could pass it as an ObservedObject + +374 +00:17:12,000 --> 00:17:15,410 +and then have another argument +here to the PaletteEditor. + +375 +00:17:15,410 --> 00:17:17,600 +But turns out there's a problem + +376 +00:17:17,600 --> 00:17:19,670 +when you do these separate Views + +377 +00:17:19,670 --> 00:17:22,290 +like popovers, and things like that. + +378 +00:17:22,290 --> 00:17:24,960 +They get their kind of +own world to live in + +379 +00:17:24,960 --> 00:17:28,900 +and you have to pass into +that world this ViewModel, + +380 +00:17:28,900 --> 00:17:32,000 +or it won't work right, bottom line. + +381 +00:17:32,000 --> 00:17:35,040 +So how do we set the environment here? + +382 +00:17:35,040 --> 00:17:38,017 +We use this .environmentObject. + +383 +00:17:40,896 --> 00:17:42,803 +And this is again, we +saw this in the slide, + +384 +00:17:42,803 --> 00:17:45,200 +this is how we pass our environment. + +385 +00:17:45,200 --> 00:17:47,670 +And in this case, this +is just our own document + +386 +00:17:47,670 --> 00:17:50,970 +being passed as the environment for this. + +387 +00:17:50,970 --> 00:17:52,830 +These EnvironmentObjects + +388 +00:17:52,830 --> 00:17:55,200 +and also @Environment to an extent + +389 +00:17:55,200 --> 00:17:58,080 +are really exactly what +their name implies: + +390 +00:17:58,080 --> 00:18:01,490 +an environment in which +this View is working. + +391 +00:18:01,490 --> 00:18:03,810 +Right, it's using, it's +working in an environment + +392 +00:18:03,810 --> 00:18:07,033 +where this is their ViewModel essentially. + +393 +00:18:08,270 --> 00:18:09,217 +So now we have the document, + +394 +00:18:09,217 --> 00:18:11,570 +we should be able to get +the name outta there. + +395 +00:18:11,570 --> 00:18:13,120 +Let's see what that looks like. + +396 +00:18:17,554 --> 00:18:20,230 +All right, so this is +our activities palette, + +397 +00:18:20,230 --> 00:18:21,830 +and sure enough, we have it there. + +398 +00:18:21,830 --> 00:18:24,440 +Let's try another one, +how about our animals? + +399 +00:18:24,440 --> 00:18:25,633 +Yeah, animals. + +400 +00:18:26,860 --> 00:18:30,860 +Our next step here is to +make this animals editable. + +401 +00:18:30,860 --> 00:18:33,340 +We want to be able to change this animals + +402 +00:18:33,340 --> 00:18:34,810 +to be something else. + +403 +00:18:34,810 --> 00:18:38,450 +So how do we make this Text editable? + +404 +00:18:38,450 --> 00:18:41,720 +We're gonna need a little +different View than Text for that. + +405 +00:18:41,720 --> 00:18:44,403 +We need a TextField. + +406 +00:18:45,280 --> 00:18:49,230 +A TextField takes a little +bit different arguments + +407 +00:18:49,230 --> 00:18:50,530 +than a Text. + +408 +00:18:50,530 --> 00:18:53,780 +The first argument it takes is its label, + +409 +00:18:53,780 --> 00:18:56,800 +and it should describe what it is + +410 +00:18:56,800 --> 00:18:58,990 +that this TextField is editing. + +411 +00:18:58,990 --> 00:19:00,320 +In our case, this is going to be + +412 +00:19:00,320 --> 00:19:01,750 +editing the name of the palette, + +413 +00:19:01,750 --> 00:19:03,490 +so we're gonna say "Palette Name". + +414 +00:19:03,490 --> 00:19:06,380 +And we'll see in the UI +where this label appears. + +415 +00:19:06,380 --> 00:19:09,170 +And it depends on the UI, +this is going to adapt + +416 +00:19:09,170 --> 00:19:12,830 +to Apple TV, Apple Watch, iOS, Mac, + +417 +00:19:12,830 --> 00:19:15,277 +it's going to do the right thing here. + +418 +00:19:15,277 --> 00:19:16,830 +And then the second argument, + +419 +00:19:16,830 --> 00:19:20,997 +the most important argument +in TextField is called text. + +420 +00:19:20,997 --> 00:19:25,750 +And it is a Binding to some String, + +421 +00:19:25,750 --> 00:19:29,100 +that is going to be what's being edited. + +422 +00:19:29,100 --> 00:19:32,680 +So this is what the TextField +is actually editing. + +423 +00:19:32,680 --> 00:19:34,630 +So we need, this is gonna be a Binding. + +424 +00:19:34,630 --> 00:19:38,340 +So I'm gonna make some +State here private var, + +425 +00:19:38,340 --> 00:19:41,540 +call my paletteName, which +is gonna be a String. + +426 +00:19:41,540 --> 00:19:44,263 +We'll initialize it to be empty to start. + +427 +00:19:45,320 --> 00:19:48,380 +And that's what this TextField +is gonna do is edit that. + +428 +00:19:48,380 --> 00:19:50,070 +Let's see what this UI looks like + +429 +00:19:50,070 --> 00:19:52,673 +with the TextField right +there instead of a Text. + +430 +00:19:53,794 --> 00:19:54,960 +Here we go. + +431 +00:19:54,960 --> 00:19:58,110 +Oop, there it is, you can +see it says, "Palette Name." + +432 +00:19:58,110 --> 00:20:01,050 +Now when I touch on it, it starts editing, + +433 +00:20:01,050 --> 00:20:03,400 +you can see it brings up the keyboard + +434 +00:20:03,400 --> 00:20:08,400 +and I could type in +"hello", or whatever I want + +435 +00:20:08,450 --> 00:20:10,360 +as the name of my palette. + +436 +00:20:10,360 --> 00:20:13,240 +So the label that we saw: "Palette Name", + +437 +00:20:13,240 --> 00:20:17,140 +it only showed up when we +had nothing in the field + +438 +00:20:17,140 --> 00:20:18,940 +when the field was completely empty. + +439 +00:20:19,840 --> 00:20:21,970 +Now normally, that's not +going to happen here, + +440 +00:20:21,970 --> 00:20:26,970 +because when we first bring +this up for some given palette, + +441 +00:20:27,210 --> 00:20:30,260 +this should probably be prefilled out + +442 +00:20:30,260 --> 00:20:33,060 +with what the current name is. + +443 +00:20:33,060 --> 00:20:35,230 +And we'd only see this label if the person + +444 +00:20:35,230 --> 00:20:38,090 +delete, delete, delete, +and made it go away, + +445 +00:20:38,090 --> 00:20:40,120 +and then like, well, +what's this field about? + +446 +00:20:40,120 --> 00:20:41,880 +They would find out about "Palette Name". + +447 +00:20:41,880 --> 00:20:45,660 +But it's pretty obvious if I go to faces + +448 +00:20:45,660 --> 00:20:49,120 +and I touch a button right +next to it, to palette editor + +449 +00:20:49,120 --> 00:20:52,313 +and it says faces right here, +that's gonna be the name. + +450 +00:20:53,150 --> 00:20:54,210 +And in the iOS, + +451 +00:20:54,210 --> 00:20:56,880 +we try not to have a +lot of extraneous labels + +452 +00:20:56,880 --> 00:20:59,210 +and things like that aren't necessary. + +453 +00:20:59,210 --> 00:21:01,640 +In this case, definitely not +necessary to have this here + +454 +00:21:01,640 --> 00:21:03,880 +unless someone deletes it all the way + +455 +00:21:03,880 --> 00:21:06,460 +then they might be like, "Oh +wait, what is this again?" + +456 +00:21:06,460 --> 00:21:07,990 +And then this prompts them for that + +457 +00:21:07,990 --> 00:21:09,933 +which is kind of cool UI. + +458 +00:21:11,470 --> 00:21:15,420 +So how do we get this to come +up with this saying faces + +459 +00:21:15,420 --> 00:21:17,690 +right here instead of being blank? + +460 +00:21:17,690 --> 00:21:20,040 +Well, because we're the +State, this paletteName, + +461 +00:21:20,040 --> 00:21:22,440 +this String that we're editing, + +462 +00:21:22,440 --> 00:21:25,670 +we initialize it right +here to nothingness. + +463 +00:21:25,670 --> 00:21:27,550 +So we need to initialize it + +464 +00:21:27,550 --> 00:21:30,630 +to be the name of the palette, right? + +465 +00:21:30,630 --> 00:21:32,910 +This thing that we have up here + +466 +00:21:32,910 --> 00:21:36,165 +that we originally had in that TextField. + +467 +00:21:36,165 --> 00:21:38,380 +I'm gonna do that with onAppear, + +468 +00:21:38,380 --> 00:21:41,730 +onAppear we're really +comfortable doing this hopefully. + +469 +00:21:41,730 --> 00:21:44,680 +I'm just going to set my paletteName + +470 +00:21:45,780 --> 00:21:48,400 +equal to my document's palette name. + +471 +00:21:48,400 --> 00:21:49,910 +And again, I could initialize it + +472 +00:21:49,910 --> 00:21:52,130 +in the same way we showed at +the beginning of this lecture, + +473 +00:21:52,130 --> 00:21:54,763 +but this is a perfectly +fine way to do it here. + +474 +00:21:58,860 --> 00:22:00,930 +And activities, yep, there it is, + +475 +00:22:00,930 --> 00:22:03,520 +and still editable can +click on it and edit it, + +476 +00:22:03,520 --> 00:22:05,920 +go over here animals, yap. + +477 +00:22:05,920 --> 00:22:07,600 +Brings up the keyboard. + +478 +00:22:07,600 --> 00:22:08,920 +Notice when it brings up the keyboard + +479 +00:22:08,920 --> 00:22:12,700 +it does scroll the breast +of the UI up a little bit + +480 +00:22:12,700 --> 00:22:16,670 +so that this is not gonna +be blocked by the keyboard. + +481 +00:22:16,670 --> 00:22:20,970 +Very important when we touch +to start editing in iOS, + +482 +00:22:20,970 --> 00:22:23,800 +especially on an iPhone +where space is limited + +483 +00:22:23,800 --> 00:22:25,350 +and the keyboard coming up + +484 +00:22:25,350 --> 00:22:26,990 +is going to cover up a lot of things. + +485 +00:22:26,990 --> 00:22:29,550 +We want it to scroll up into +a place where it's editable, + +486 +00:22:29,550 --> 00:22:32,073 +so it automatically does that for us. + +487 +00:22:33,560 --> 00:22:34,677 +Now, what if I change this? + +488 +00:22:34,677 --> 00:22:39,677 +What if I change this from +animals to let's say, beasts? + +489 +00:22:43,810 --> 00:22:46,390 +If I say animals to +beasts, and there it is, + +490 +00:22:46,390 --> 00:22:48,330 +and it didn't change anything. + +491 +00:22:48,330 --> 00:22:51,330 +This still says animals right +here but this says beasts. + +492 +00:22:51,330 --> 00:22:53,730 +Now, it still says animals and now I got, + +493 +00:22:53,730 --> 00:22:56,410 +it never changed it, how +come it never changed it? + +494 +00:22:56,410 --> 00:23:00,450 +Well, we when we're over +here editing our TextField, + +495 +00:23:00,450 --> 00:23:03,090 +we're editing this local State. + +496 +00:23:03,090 --> 00:23:06,730 +We're not editing back +in our document anywhere. + +497 +00:23:06,730 --> 00:23:10,300 +So when this changes, whenever +this TextField changes, + +498 +00:23:10,300 --> 00:23:14,400 +we need to set our document's +palette name for that, + +499 +00:23:14,400 --> 00:23:17,000 +rename that palette to be that. + +500 +00:23:17,000 --> 00:23:18,803 +We do that with another +argument to TextField, + +501 +00:23:18,803 --> 00:23:21,240 +it's called onEditingChanged, + +502 +00:23:22,269 --> 00:23:24,070 +and it just takes a little closure. + +503 +00:23:24,070 --> 00:23:28,730 +Now this closure has one argument, +I call it usually, began. + +504 +00:23:28,730 --> 00:23:30,930 +This argument is whether +the editing changed + +505 +00:23:30,930 --> 00:23:34,300 +because editing started, +began in the TextField + +506 +00:23:34,300 --> 00:23:35,980 +or because it ended. + +507 +00:23:35,980 --> 00:23:38,460 +So this is began or ended. + +508 +00:23:38,460 --> 00:23:41,740 +So in our case, we only wanna +update our palette's name + +509 +00:23:41,740 --> 00:23:44,060 +or rename our palette +when the editing ends. + +510 +00:23:44,060 --> 00:23:48,147 +So I'm gonna say if !began, +then what am I gonna do? + +511 +00:23:48,147 --> 00:23:53,147 +I'm gonna tell my document +to rename this palette, + +512 +00:23:53,610 --> 00:23:57,730 +the chosenPalette to this +name that was just chosen + +513 +00:23:57,730 --> 00:23:59,963 +which is the paletteName. + +514 +00:24:02,090 --> 00:24:04,870 +Simple as that, I'm just +gonna rename my palette + +515 +00:24:04,870 --> 00:24:06,800 +so my document gets the message + +516 +00:24:06,800 --> 00:24:08,573 +that we just edited this thing. + +517 +00:24:13,210 --> 00:24:14,920 +So I can still go through here. + +518 +00:24:14,920 --> 00:24:18,980 +Now if I wanna rename animals +to beasts, I can go to animals + +519 +00:24:18,980 --> 00:24:21,050 +click on it right here, +it says, "Animals." + +520 +00:24:21,050 --> 00:24:22,663 +We'll back up here. + +521 +00:24:23,530 --> 00:24:25,763 +We'll type "Beasts". + +522 +00:24:28,330 --> 00:24:30,850 +We're done editing, we can +dismiss the keyboard right here, + +523 +00:24:30,850 --> 00:24:33,600 +or we could click away. + +524 +00:24:33,600 --> 00:24:34,830 +And we're changing it, see? + +525 +00:24:34,830 --> 00:24:36,450 +When we finished editing there, + +526 +00:24:36,450 --> 00:24:39,383 +when editing was done +happening, it changed. + +527 +00:24:40,950 --> 00:24:42,990 +Let's use another TextField now, + +528 +00:24:42,990 --> 00:24:44,780 +to be able to add emojis up here. + +529 +00:24:44,780 --> 00:24:47,935 +We wanna add emojis to our list. + +530 +00:24:47,935 --> 00:24:49,010 +This is so similar, + +531 +00:24:49,010 --> 00:24:51,670 +I'm actually going to take +this TextField right here + +532 +00:24:52,510 --> 00:24:55,920 +and copy and paste it and +make another TextField. + +533 +00:24:55,920 --> 00:24:59,810 +This is the "Add Emoji" +TextField, that's its label. + +534 +00:24:59,810 --> 00:25:01,530 +Instead of editing the paletteName, + +535 +00:25:01,530 --> 00:25:04,417 +we're gonna edit something +called $emojisToAdd. + +536 +00:25:05,750 --> 00:25:10,080 +And when this one changes, +instead of renaming the palette, + +537 +00:25:10,080 --> 00:25:15,080 +we're going to ask our +document to add emoji, + +538 +00:25:15,620 --> 00:25:17,800 +these emojis to add + +539 +00:25:19,440 --> 00:25:21,053 +to this palette, + +540 +00:25:23,564 --> 00:25:24,731 +chosenPalette. + +541 +00:25:25,880 --> 00:25:28,370 +And of course, adding +emojis to our chosenPalette + +542 +00:25:28,370 --> 00:25:30,920 +is going to change our chosenPalette. + +543 +00:25:30,920 --> 00:25:34,410 +So we're gonna update +our own State to do that. + +544 +00:25:34,410 --> 00:25:39,410 +And also, let's set our +emojisToAdd here equal to empty + +545 +00:25:40,570 --> 00:25:42,760 +because we just added these emojis, + +546 +00:25:42,760 --> 00:25:46,227 +we don't really need to leave +them in the emojisToAdd, + +547 +00:25:46,227 --> 00:25:47,500 +we're not gonna add them again. + +548 +00:25:47,500 --> 00:25:50,820 +In fact, my addEmoji here in my document + +549 +00:25:50,820 --> 00:25:52,800 +doesn't allow you to add +the same emoji twice. + +550 +00:25:52,800 --> 00:25:54,830 +It just moves the emoji +to the front of the list + +551 +00:25:54,830 --> 00:25:56,790 +if you add it twice. + +552 +00:25:56,790 --> 00:25:58,730 +And of course we need this State as well. + +553 +00:25:58,730 --> 00:26:02,473 +So at @State private var emojisToAdd. + +554 +00:26:03,982 --> 00:26:07,093 +This is a String, we'll start +that also empty as well. + +555 +00:26:08,791 --> 00:26:09,763 +Let's see this. + +556 +00:26:13,508 --> 00:26:15,677 +And activities, there it is! + +557 +00:26:17,030 --> 00:26:18,800 +So let's click on here to add some emoji, + +558 +00:26:18,800 --> 00:26:23,010 +we'll go to the emoji keyboard, +all iOS keyboards have that. + +559 +00:26:23,010 --> 00:26:25,870 +This is activities, so let's +go over to our activities. + +560 +00:26:25,870 --> 00:26:29,089 +Maybe we add some bike riders here. + +561 +00:26:29,089 --> 00:26:30,263 +Then golfers. + +562 +00:26:35,167 --> 00:26:38,200 +And there it is, added it +right there to our document, + +563 +00:26:38,200 --> 00:26:39,180 +no problem. + +564 +00:26:46,321 --> 00:26:47,238 +Snowborder. + +565 +00:26:49,110 --> 00:26:49,943 +Archery. + +566 +00:26:56,050 --> 00:26:58,150 +When we start having a UI though, + +567 +00:26:58,150 --> 00:26:59,960 +that's adding multiple things here. + +568 +00:26:59,960 --> 00:27:01,390 +And we're even gonna add another section + +569 +00:27:01,390 --> 00:27:03,010 +for removing emojis. + +570 +00:27:03,010 --> 00:27:06,870 +We don't want them to be kind +of open in outer space here + +571 +00:27:06,870 --> 00:27:11,870 +just spaced out with no kind +of cohesion to them or no form. + +572 +00:27:12,560 --> 00:27:14,750 +And so there is an awesome little View + +573 +00:27:14,750 --> 00:27:16,600 +that you can use to give + +574 +00:27:16,600 --> 00:27:21,600 +a set of fields like this +some form, it's called Form. + +575 +00:27:22,350 --> 00:27:25,653 +So we're gonna put a Form around this. + +576 +00:27:25,653 --> 00:27:28,373 +This is what it looks +like to put a Form around. + +577 +00:27:29,285 --> 00:27:33,403 +We put the Form right here +around these two TextFields. + +578 +00:27:35,220 --> 00:27:37,070 +And one thing that's nice about Form + +579 +00:27:37,070 --> 00:27:39,710 +is it was automatically scrollable space + +580 +00:27:39,710 --> 00:27:41,410 +that will deal with the fact + +581 +00:27:41,410 --> 00:27:42,370 +that we have space at the bottom + +582 +00:27:42,370 --> 00:27:44,770 +so we do not need the +Spacer anymore there. + +583 +00:27:44,770 --> 00:27:48,190 +The Form will use all of its +space, it's one of these Views + +584 +00:27:48,190 --> 00:27:50,210 +that takes all the space offered to it. + +585 +00:27:50,210 --> 00:27:52,130 +We don't use Spacer there. + +586 +00:27:52,130 --> 00:27:54,170 +Forms also can be divided into Sections. + +587 +00:27:54,170 --> 00:27:56,670 +For example, we could have a Section here + +588 +00:27:56,670 --> 00:28:00,640 +which is our "Palette Name" Section. + +589 +00:28:05,300 --> 00:28:06,570 +We also don't need padding, + +590 +00:28:06,570 --> 00:28:08,910 +Form takes care of all the padding, + +591 +00:28:08,910 --> 00:28:11,703 +it's laying out all these things itself. + +592 +00:28:11,703 --> 00:28:14,650 +Have another Section here, +maybe this Section has no title, + +593 +00:28:14,650 --> 00:28:16,363 +that's allowed as well. + +594 +00:28:18,340 --> 00:28:19,190 +Let's see what this looks like. + +595 +00:28:19,190 --> 00:28:23,490 +So we added a Form right here, +Section for the palette name + +596 +00:28:23,490 --> 00:28:25,523 +and a Section for "Add Emoji". + +597 +00:28:29,353 --> 00:28:30,810 +(sighs) Look at our Form. + +598 +00:28:30,810 --> 00:28:33,010 +You've probably seen +Forms like this before, + +599 +00:28:33,010 --> 00:28:34,490 +like even in the Settings app + +600 +00:28:34,490 --> 00:28:36,930 +that we've seen this kind of look. + +601 +00:28:36,930 --> 00:28:38,580 +Now, it's a little bit redundant actually, + +602 +00:28:38,580 --> 00:28:42,110 +to have a section title +name here palette name + +603 +00:28:42,110 --> 00:28:45,440 +when we know that if we +edit this down to zero, + +604 +00:28:45,440 --> 00:28:47,470 +we're gonna get the +"Palette Name" there too. + +605 +00:28:47,470 --> 00:28:50,660 +So I probably would not have +a header with the exact same + +606 +00:28:50,660 --> 00:28:52,463 +name as the TextField in it. + +607 +00:28:53,391 --> 00:28:54,900 +And in fact, I'm not even sure + +608 +00:28:54,900 --> 00:28:57,210 +I would make this two separate Sections. + +609 +00:28:57,210 --> 00:29:00,323 +I might put them both in +the same Section right here. + +610 +00:29:03,470 --> 00:29:07,273 +Makes it a little bit cleaner +UI, you can see it's still put + +611 +00:29:07,273 --> 00:29:09,990 +kind of a little special divider line + +612 +00:29:09,990 --> 00:29:13,203 +and I can still go and +add my emoji right here. + +613 +00:29:17,790 --> 00:29:19,710 +But sometimes you do want Sections. + +614 +00:29:19,710 --> 00:29:23,010 +For example, I'm gonna add a +Section here to remove emojis, + +615 +00:29:23,010 --> 00:29:26,480 +and it's going to want to be +its own Section, as you'll see. + +616 +00:29:26,480 --> 00:29:27,530 +So let's go ahead and do that. + +617 +00:29:27,530 --> 00:29:29,973 +Add a remove emoji section. + +618 +00:29:32,250 --> 00:29:36,270 +Section, header, Text, + +619 +00:29:36,270 --> 00:29:37,883 +"Remove Emoji". + +620 +00:29:40,260 --> 00:29:43,547 +And in here, I essentially +wanna do a ForEach + +621 +00:29:45,390 --> 00:29:49,370 +on all of my chosen palettes' emojis, + +622 +00:29:49,370 --> 00:29:53,623 +so I'll map them to +Strings as we did before. + +623 +00:29:54,610 --> 00:29:57,580 +And, of course, these are not Identifiable + +624 +00:29:57,580 --> 00:30:01,470 +so we'll have to do id +identifiable on self. + +625 +00:30:01,470 --> 00:30:03,643 +And for each of the emojis in here, + +626 +00:30:04,640 --> 00:30:09,640 +we will just put them in +a little Text like this. + +627 +00:30:09,700 --> 00:30:11,163 +And when you tap on them, + +628 +00:30:12,705 --> 00:30:15,963 +it will remove them +from our chosen palette. + +629 +00:30:18,746 --> 00:30:21,010 +And of course the ForEach +doesn't lay them out + +630 +00:30:21,010 --> 00:30:22,520 +in any particular way. + +631 +00:30:22,520 --> 00:30:24,640 +So let's go ahead and put them in + +632 +00:30:24,640 --> 00:30:26,180 +I'll say a VStack for now. + +633 +00:30:26,180 --> 00:30:27,550 +I think we can do better than that + +634 +00:30:27,550 --> 00:30:30,644 +but we'll start by +putting them in a VStack. + +635 +00:30:30,644 --> 00:30:34,550 +So I'm just gonna stack up +all my emojis right there + +636 +00:30:34,550 --> 00:30:37,013 +and click on 'em to remove. + +637 +00:30:40,440 --> 00:30:42,810 +There we go, look at that, +there's all our emojis. + +638 +00:30:42,810 --> 00:30:44,030 +Let's try removing some. + +639 +00:30:44,030 --> 00:30:47,930 +Let's decide, we don't +want the golfer, gone. + +640 +00:30:47,930 --> 00:30:52,040 +We don't want this soccer ball, gone. + +641 +00:30:52,040 --> 00:30:55,840 +We don't want the surfer, +snowboarder, gone. + +642 +00:30:55,840 --> 00:30:58,100 +The only problem with this emoji thing + +643 +00:30:58,100 --> 00:30:59,503 +is it's kind of a yucky UI. + +644 +00:31:00,580 --> 00:31:02,760 +To have this in a long list like this, + +645 +00:31:02,760 --> 00:31:06,350 +it'd be nicer if it was +like in a grid, for example. + +646 +00:31:06,350 --> 00:31:08,460 +And we have a Grid from Memorize. + +647 +00:31:08,460 --> 00:31:11,300 +Let's see if we can use our +Grid from Memorize in here. + +648 +00:31:11,300 --> 00:31:12,640 +It'll make it look better, + +649 +00:31:12,640 --> 00:31:14,720 +and it's also gonna help us understand + +650 +00:31:14,720 --> 00:31:19,710 +even a little bit more about +protocols and don't cares, + +651 +00:31:19,710 --> 00:31:22,883 +and constrains and gains and all that. + +652 +00:31:24,410 --> 00:31:26,840 +Let's start by hopping over to Memorize + +653 +00:31:26,840 --> 00:31:28,440 +and grabbing Grid outta there. + +654 +00:31:28,440 --> 00:31:33,440 +I'm just gonna go over +here to Developer here. + +655 +00:31:33,473 --> 00:31:36,660 +I'll go to Memorize, here's +Memorize, I'm gonna grab Grid + +656 +00:31:36,660 --> 00:31:39,520 +and of course, we need GridLayout as well + +657 +00:31:39,520 --> 00:31:41,523 +and drag them over here. + +658 +00:31:42,470 --> 00:31:44,783 +And we do wanna copy the items there. + +659 +00:31:50,086 --> 00:31:52,530 +So this is the same +Grid we had in Memorize, + +660 +00:31:52,530 --> 00:31:54,770 +no changes to it whatsoever. + +661 +00:31:54,770 --> 00:31:58,400 +And I'd like to use it instead +of this VStack and ForEach, + +662 +00:31:58,400 --> 00:32:00,210 +remember our Grid kinda combines that. + +663 +00:32:00,210 --> 00:32:04,570 +So I'm gonna say Grid, get rid +of one of these curly braces. + +664 +00:32:04,570 --> 00:32:08,020 +And this would be really +nice to do like this. + +665 +00:32:08,020 --> 00:32:10,630 +Unfortunately, this is not going to work. + +666 +00:32:10,630 --> 00:32:13,920 +Because our Grid doesn't +understand how to do + +667 +00:32:13,920 --> 00:32:17,030 +this id self business, right? + +668 +00:32:17,030 --> 00:32:20,400 +Our grid requires that +everything that's passed to it + +669 +00:32:20,400 --> 00:32:22,560 +be Identifiable. + +670 +00:32:22,560 --> 00:32:27,560 +See, Item Identifiable, these +Items have to be Identifiable. + +671 +00:32:27,900 --> 00:32:30,650 +So let's take a little time +out from building our UI + +672 +00:32:30,650 --> 00:32:33,620 +and understand how we +could change our Grid + +673 +00:32:33,620 --> 00:32:37,180 +so that it did take an id argument here + +674 +00:32:37,180 --> 00:32:38,630 +that let us specify + +675 +00:32:40,010 --> 00:32:44,330 +what KeyPath to use to find the ID. + +676 +00:32:44,330 --> 00:32:47,490 +Just like we do here, wanna pass this. + +677 +00:32:47,490 --> 00:32:50,130 +So what is this little thing right here? + +678 +00:32:50,130 --> 00:32:52,270 +We've talked about it a few times. + +679 +00:32:52,270 --> 00:32:53,820 +It is a KeyPath. + +680 +00:32:53,820 --> 00:32:57,750 +It's something that just +specifies a certain var to access + +681 +00:32:57,750 --> 00:32:59,047 +on an instance of an object. + +682 +00:32:59,047 --> 00:33:02,730 +And in this case, I'm doing +self because these are Strings + +683 +00:33:02,730 --> 00:33:04,610 +and the String.self is the String itself. + +684 +00:33:04,610 --> 00:33:08,361 +And that's a good thing +to be Identifiable. + +685 +00:33:08,361 --> 00:33:10,160 +That works great. + +686 +00:33:10,160 --> 00:33:12,350 +So how do we say what this type is? + +687 +00:33:12,350 --> 00:33:15,610 +Because if we're gonna have +this passed as a type here + +688 +00:33:15,610 --> 00:33:18,230 +to our id, we have to say what it is. + +689 +00:33:18,230 --> 00:33:23,230 +Its type is KeyPath, and +it has two don't cares. + +690 +00:33:23,650 --> 00:33:28,650 +One is the kind of object that +you are looking for a var on. + +691 +00:33:29,750 --> 00:33:31,970 +In our case, this is Item. + +692 +00:33:31,970 --> 00:33:34,405 +This is the things that +in this Array over here, + +693 +00:33:34,405 --> 00:33:35,970 +KeyPath Item. + +694 +00:33:35,970 --> 00:33:39,920 +The second don't care is +the return value of it. + +695 +00:33:39,920 --> 00:33:43,560 +Now, we really don't care what +you use as your Identifiable. + +696 +00:33:43,560 --> 00:33:45,947 +So our return type is going +to be a don't care for us. + +697 +00:33:45,947 --> 00:33:49,950 +I'm gonna call it ID, +and I'll put it up there. + +698 +00:33:49,950 --> 00:33:52,680 +And that is how we can specify this ID. + +699 +00:33:52,680 --> 00:33:57,680 +And now we have this ID, let's +go ahead and set it as a var. + +700 +00:33:57,980 --> 00:33:59,170 +Hold on to it. + +701 +00:33:59,170 --> 00:34:01,450 +So we're gonna need a private var + +702 +00:34:01,450 --> 00:34:05,763 +that's of type KeyPath<Item, ID>. + +703 +00:34:07,120 --> 00:34:10,670 +And almost there, let's go down +here to here's our ForEach, + +704 +00:34:10,670 --> 00:34:15,670 +and we will just pass this id, +our own id var right there. + +705 +00:34:16,650 --> 00:34:17,833 +This should work, right? + +706 +00:34:17,833 --> 00:34:20,750 +This is pretty much +everything we would need. + +707 +00:34:20,750 --> 00:34:22,480 +But we have a little bit of a problem, + +708 +00:34:22,480 --> 00:34:24,713 +we got a constrains +and gains problem here. + +709 +00:34:25,590 --> 00:34:29,580 +Says here, "Generic struct +ForEach requires that ID," + +710 +00:34:29,580 --> 00:34:33,120 +this ID conform to Hashable. + +711 +00:34:33,120 --> 00:34:34,530 +Which kind of makes sense, right? + +712 +00:34:34,530 --> 00:34:36,300 +What does a ForEach do? + +713 +00:34:36,300 --> 00:34:38,460 +Looks at all it's items +and for each of one, + +714 +00:34:38,460 --> 00:34:42,050 +it builds this View +for it, which is great, + +715 +00:34:42,050 --> 00:34:44,270 +but it probably has to keep these items + +716 +00:34:44,270 --> 00:34:47,020 +in some sort of Dictionary +or hash table or something + +717 +00:34:47,020 --> 00:34:48,840 +so that it can know which View + +718 +00:34:48,840 --> 00:34:50,700 +is associated with them, et cetera. + +719 +00:34:50,700 --> 00:34:53,040 +So it's perfectly reasonable to expect + +720 +00:34:53,040 --> 00:34:55,290 +that ID has to be Hashable here. + +721 +00:34:55,290 --> 00:34:59,680 +But ID for us is the return +value from this KeyPath here, + +722 +00:34:59,680 --> 00:35:02,140 +that is a don't care. + +723 +00:35:02,140 --> 00:35:05,540 +But evidently we care a +little bit about this type ID + +724 +00:35:05,540 --> 00:35:07,400 +that's a return value from the KeyPath. + +725 +00:35:07,400 --> 00:35:09,653 +It's going to have to be Hashable. + +726 +00:35:10,843 --> 00:35:13,416 +So I'm gonna mark it to be Hashable, + +727 +00:35:13,416 --> 00:35:15,270 +and just require that this don't care, + +728 +00:35:15,270 --> 00:35:17,210 +whatever it is be Hashable. + +729 +00:35:17,210 --> 00:35:19,760 +And while I'm at it, I can +get rid of Item Identifiable. + +730 +00:35:19,760 --> 00:35:22,110 +That's kind of the whole +point is to make it + +731 +00:35:22,110 --> 00:35:25,163 +so that our Item doesn't +have to be Identifiable. + +732 +00:35:26,150 --> 00:35:29,070 +So we're almost there, +actually, but we have a problem + +733 +00:35:29,070 --> 00:35:31,420 +in that we use this firstIndex matching, + +734 +00:35:31,420 --> 00:35:33,210 +remember, firstIndex matching. + +735 +00:35:33,210 --> 00:35:37,080 +It's the function that we added to Array + +736 +00:35:37,080 --> 00:35:38,750 +into a Collection actually, + +737 +00:35:38,750 --> 00:35:43,570 +that looks something up +by its Identifiable-ness. + +738 +00:35:43,570 --> 00:35:45,630 +Well, our Items are no +longer Identifiable, + +739 +00:35:45,630 --> 00:35:47,540 +I stopped making them Identifiable. + +740 +00:35:47,540 --> 00:35:50,520 +However, we do have this ID, this KeyPath + +741 +00:35:50,520 --> 00:35:52,370 +that we can use on an Item + +742 +00:35:52,370 --> 00:35:56,150 +to find out an Identifiable +thing on it, Hashable thing. + +743 +00:35:56,150 --> 00:35:59,330 +So how are we gonna replace +firstIndex of item with + +744 +00:35:59,330 --> 00:36:01,086 +using this ID? + +745 +00:36:01,086 --> 00:36:05,750 +Well, I'm gonna do firstIndex, +a different one called where, + +746 +00:36:05,750 --> 00:36:09,100 +and where takes some closure here. + +747 +00:36:09,100 --> 00:36:13,060 +And this closure is +given each of the things, + +748 +00:36:13,060 --> 00:36:14,410 +Items in the Array. + +749 +00:36:14,410 --> 00:36:18,243 +So we'll use the built-in +argument which will be $0. + +750 +00:36:19,560 --> 00:36:22,490 +And it lets you do something with it + +751 +00:36:22,490 --> 00:36:25,423 +and return true when it matches. + +752 +00:36:26,920 --> 00:36:31,880 +We want this KeyPath out of our item. + +753 +00:36:31,880 --> 00:36:36,850 +And we wanna compare this +KeyPath out of the $0 + +754 +00:36:36,850 --> 00:36:39,870 +in the items Array to +see if they're the same. + +755 +00:36:39,870 --> 00:36:44,180 +So here's how you take +an Item and use a KeyPath + +756 +00:36:44,180 --> 00:36:46,150 +to go get the value of the var + +757 +00:36:46,150 --> 00:36:48,240 +that that KeyPath is talking about it. + +758 +00:36:48,240 --> 00:36:52,270 +You say, [keyPath: + +759 +00:36:52,270 --> 00:36:54,530 +and the KeyPath. + +760 +00:36:54,530 --> 00:36:59,530 +So this expression right here +means call this KeyPath var + +761 +00:37:00,150 --> 00:37:03,070 +on this Item and give it to us. + +762 +00:37:03,070 --> 00:37:05,147 +And we're just gonna check +to see if that equals + +763 +00:37:05,147 --> 00:37:08,853 +$0's KeyPath of that id. + +764 +00:37:10,700 --> 00:37:14,590 +A lot going on here, hopefully, +you guys are following this, + +765 +00:37:14,590 --> 00:37:16,700 +I would say you don't +really have to understand + +766 +00:37:16,700 --> 00:37:19,060 +what I just did here to use SwiftUI. + +767 +00:37:19,060 --> 00:37:21,470 +But if you do, you're really understanding + +768 +00:37:21,470 --> 00:37:24,113 +this constrains and gains +of what's going on here. + +769 +00:37:28,750 --> 00:37:31,393 +But let's take this even one step further. + +770 +00:37:32,300 --> 00:37:35,180 +This, unfortunately, has kind of broken + +771 +00:37:35,180 --> 00:37:37,060 +the old way we used to use Grid. + +772 +00:37:37,060 --> 00:37:41,380 +Now we're forced to do this ID KeyPath + +773 +00:37:41,380 --> 00:37:43,660 +even if our Item is Identifiable, + +774 +00:37:43,660 --> 00:37:45,440 +we still have to provide this argument. + +775 +00:37:45,440 --> 00:37:48,170 +This argument doesn't default to anything. + +776 +00:37:48,170 --> 00:37:50,330 +So let's look how we could + +777 +00:37:50,330 --> 00:37:53,450 +take this exact same code +that we just modified + +778 +00:37:53,450 --> 00:37:55,980 +and change it so it'd still +work with the old world. + +779 +00:37:55,980 --> 00:37:59,260 +And this will really get you +with the constrains and gains. + +780 +00:37:59,260 --> 00:38:01,520 +So I'm gonna make an extension to Grid. + +781 +00:38:01,520 --> 00:38:05,230 +And in this extension, +I'm going to require + +782 +00:38:05,230 --> 00:38:08,760 +that items be Identifiable. + +783 +00:38:08,760 --> 00:38:10,470 +So that's only gonna be in this extension + +784 +00:38:10,470 --> 00:38:11,850 +that they're Identifiable. + +785 +00:38:11,850 --> 00:38:14,590 +And then I wanna add a new init, + +786 +00:38:14,590 --> 00:38:18,250 +where it takes the items +just as we did before, + +787 +00:38:18,250 --> 00:38:20,690 +and does not take that id argument. + +788 +00:38:20,690 --> 00:38:23,820 +But still, of course, has the viewForItem. + +789 +00:38:23,820 --> 00:38:25,560 +And I wanna be able to +call this other init, + +790 +00:38:25,560 --> 00:38:29,720 +the one that I made down here +with all the right arguments + +791 +00:38:29,720 --> 00:38:31,720 +to make this just work. + +792 +00:38:31,720 --> 00:38:33,100 +So let's try it. + +793 +00:38:33,100 --> 00:38:35,970 +Got the items, got the id. + +794 +00:38:35,970 --> 00:38:40,470 +So we know that Identifiables +have a var on them called id + +795 +00:38:41,470 --> 00:38:42,470 +to make them Identifiable. + +796 +00:38:42,470 --> 00:38:47,470 +So what if I just say +\Item.id and then viewForItem? + +797 +00:38:48,360 --> 00:38:50,580 +This word could just do this? + +798 +00:38:50,580 --> 00:38:52,520 +Oh, not quite. + +799 +00:38:52,520 --> 00:38:56,347 +Says here, "Key path value +Item.ID cannot be converted + +800 +00:38:56,347 --> 00:38:58,140 +"to a contextual type ID." + +801 +00:38:58,140 --> 00:39:01,640 +In other words, our ID don't +care is not necessarily + +802 +00:39:01,640 --> 00:39:05,600 +the same type as this Identifiable's .id, + +803 +00:39:05,600 --> 00:39:08,260 +which is its don't care +for the Identifiable. + +804 +00:39:08,260 --> 00:39:12,957 +But we can actually force +that too, by saying, ID, + +805 +00:39:14,480 --> 00:39:19,200 +its type equals the Item's ID, + +806 +00:39:19,200 --> 00:39:23,340 +This ID right here is the +don't care for Identifiable, + +807 +00:39:23,340 --> 00:39:26,120 +and this ID is our don't care. + +808 +00:39:26,120 --> 00:39:29,100 +So by forcing these to be the same, + +809 +00:39:29,100 --> 00:39:31,850 +we make it so that we can call this init. + +810 +00:39:33,610 --> 00:39:34,880 +This is the kinda thing you can do + +811 +00:39:34,880 --> 00:39:36,050 +with constrains and gains. + +812 +00:39:36,050 --> 00:39:39,150 +A little bit advanced topic here, + +813 +00:39:39,150 --> 00:39:42,770 +but it makes it so the old +Grid initializer here will work + +814 +00:39:42,770 --> 00:39:45,163 +and the new Grid initializer will work. + +815 +00:39:47,230 --> 00:39:49,490 +All right, enough of a time out there + +816 +00:39:49,490 --> 00:39:52,730 +should make it so that our +Grid right here will work. + +817 +00:39:52,730 --> 00:39:54,880 +And let's see what +happens when we do this. + +818 +00:39:56,983 --> 00:39:57,963 +All right, ready? + +819 +00:39:59,890 --> 00:40:02,430 +Well, it's not vertical +anymore, it's horizontal. + +820 +00:40:02,430 --> 00:40:05,640 +And this is actually the +Grid doing what it was asked. + +821 +00:40:05,640 --> 00:40:09,300 +It took this little space that +it was offered, this line, + +822 +00:40:09,300 --> 00:40:12,630 +which is what Forms offer +there, the things there. + +823 +00:40:12,630 --> 00:40:13,780 +Took this little space, + +824 +00:40:13,780 --> 00:40:16,490 +and it made all the emoji fit in there. + +825 +00:40:16,490 --> 00:40:19,470 +And this is the best way +you can make 'em fit. + +826 +00:40:19,470 --> 00:40:23,210 +What we really wanna do is to +offer this thing more space. + +827 +00:40:23,210 --> 00:40:25,020 +we want this to be taller, + +828 +00:40:25,020 --> 00:40:27,550 +we want this little white +rectangle to be taller. + +829 +00:40:27,550 --> 00:40:30,600 +I'm gonna do that with frame as well. + +830 +00:40:30,600 --> 00:40:32,027 +I'm gonna give this thing a height. + +831 +00:40:32,027 --> 00:40:33,690 +And I'm gonna have it's height, + +832 +00:40:33,690 --> 00:40:36,680 +I'm gonna give more height +when there's more emoji. + +833 +00:40:36,680 --> 00:40:39,277 +The more emoji we have, the +more height I'm gonna give you. + +834 +00:40:39,277 --> 00:40:42,270 +And that should make them +be spaced out about the same + +835 +00:40:42,270 --> 00:40:43,103 +no matter how many emoji you have. + +836 +00:40:43,103 --> 00:40:45,830 +If you have 1,000 I'm gonna +give you a lot of height. + +837 +00:40:45,830 --> 00:40:47,140 +If you have just three or four, + +838 +00:40:47,140 --> 00:40:50,270 +I'm just gonna give you +this tiny little height. + +839 +00:40:50,270 --> 00:40:52,310 +Well, how the heck do we do that? + +840 +00:40:52,310 --> 00:40:53,420 +Very simple. + +841 +00:40:53,420 --> 00:40:58,420 +This gGid, I'm going to +give it a fixed height. + +842 +00:40:58,631 --> 00:41:02,943 +And I'm gonna just have a +var for that, var height. + +843 +00:41:03,783 --> 00:41:05,270 +CGFloat. + +844 +00:41:05,270 --> 00:41:06,550 +I'm gonna calculate it. + +845 +00:41:06,550 --> 00:41:08,220 +I played around with this and I came up + +846 +00:41:08,220 --> 00:41:12,920 +with something like this +CGFloat chosenPalette.count + +847 +00:41:12,920 --> 00:41:17,920 +minus one divided by six times 70 plus 70. + +848 +00:41:20,130 --> 00:41:25,130 +That seemed to be the kind of best fit + +849 +00:41:25,210 --> 00:41:27,697 +for making these things +spread themselves out. + +850 +00:41:27,697 --> 00:41:30,960 +And you can go play with +that math yourself later. + +851 +00:41:30,960 --> 00:41:32,180 +Let's see. + +852 +00:41:32,180 --> 00:41:34,370 +Yeah, it's pretty good. + +853 +00:41:34,370 --> 00:41:35,510 +And I just would like these images + +854 +00:41:35,510 --> 00:41:37,110 +to be a little bigger though, + +855 +00:41:37,110 --> 00:41:40,060 +since I've given them a +nice little amount of space. + +856 +00:41:40,060 --> 00:41:44,360 +I'll do that by setting +this font size right here + +857 +00:41:44,360 --> 00:41:47,350 +Font.system size. + +858 +00:41:47,350 --> 00:41:50,280 +Let's go ahead and have +a self.fontSize as well. + +859 +00:41:50,280 --> 00:41:55,280 +These things down here are +essentially drawing constants, + +860 +00:41:55,350 --> 00:42:00,350 +height and also let our +fontSize be let's say around 40. + +861 +00:42:02,180 --> 00:42:05,063 +Seems like a good size for those things. + +862 +00:42:07,669 --> 00:42:09,710 +Here we go, and this +should still work here. + +863 +00:42:09,710 --> 00:42:12,070 +This is still a grid, it +knows how to show things. + +864 +00:42:12,070 --> 00:42:15,340 +So let's get rid of the +football, tennis ball. + +865 +00:42:15,340 --> 00:42:17,210 +This is not an activity. + +866 +00:42:17,210 --> 00:42:18,043 +There we go. + +867 +00:42:21,260 --> 00:42:24,820 +So this looks great, it's +a nice, compact little UI, + +868 +00:42:24,820 --> 00:42:26,810 +makes it really easy for +people to go through, + +869 +00:42:26,810 --> 00:42:30,860 +change the emoji that they want inside + +870 +00:42:30,860 --> 00:42:33,193 +each of their palettes right here. + +871 +00:42:34,081 --> 00:42:35,330 +And I'm gonna show you some other ways + +872 +00:42:35,330 --> 00:42:36,400 +to present this though. + +873 +00:42:36,400 --> 00:42:39,670 +This is a popover makes +perfect sense on the iPad here, + +874 +00:42:39,670 --> 00:42:41,690 +there's another way to present it on iPad, + +875 +00:42:41,690 --> 00:42:45,070 +which instead of using +a popover right here, + +876 +00:42:45,070 --> 00:42:47,570 +we use something called a sheet. + +877 +00:42:47,570 --> 00:42:49,923 +So sheet looks like this. + +878 +00:42:53,882 --> 00:42:56,640 +It's larger, it's good for UIs + +879 +00:42:56,640 --> 00:42:58,940 +that take up a lot of space obviously. + +880 +00:42:58,940 --> 00:43:02,600 +Probably for our purposes, +the popover's better, + +881 +00:43:02,600 --> 00:43:04,680 +this really doesn't need to be this large, + +882 +00:43:04,680 --> 00:43:07,320 +you're never gonna have +really long names of palette, + +883 +00:43:07,320 --> 00:43:10,560 +you're probably not gonna +be adding 100 emoji at once. + +884 +00:43:10,560 --> 00:43:14,610 +And this doesn't need to +be so spaced out as this. + +885 +00:43:14,610 --> 00:43:17,650 +And these things can be dismissed, + +886 +00:43:17,650 --> 00:43:19,190 +not by clicking away though. + +887 +00:43:19,190 --> 00:43:21,790 +See I'm clicking, touching outside, + +888 +00:43:21,790 --> 00:43:25,060 +you swipe them down to make them go away. + +889 +00:43:25,060 --> 00:43:28,260 +Now, I find that this swiping down, + +890 +00:43:28,260 --> 00:43:32,270 +it's a little bit of a +hidden UI to be swiping down + +891 +00:43:32,270 --> 00:43:34,040 +to make this go away. + +892 +00:43:34,040 --> 00:43:35,860 +So if I were doing this in a sheet, + +893 +00:43:35,860 --> 00:43:38,400 +I would probably put a +little "Done" button, + +894 +00:43:38,400 --> 00:43:40,930 +or like a close button +or something up here. + +895 +00:43:40,930 --> 00:43:42,490 +Done is usually a good word for it, + +896 +00:43:42,490 --> 00:43:45,090 +it means that you're done with this thing. + +897 +00:43:45,090 --> 00:43:48,160 +So how would we put a Button in this UI + +898 +00:43:48,160 --> 00:43:52,460 +that when we clicked it +caused it to dismiss itself? + +899 +00:43:52,460 --> 00:43:55,370 +That's a really good +thing to know how to do. + +900 +00:43:55,370 --> 00:43:57,850 +Let's put that "Done" +Button in there first. + +901 +00:43:57,850 --> 00:43:59,940 +And to do that, here's the title bar, + +902 +00:43:59,940 --> 00:44:02,210 +that "Palette Editor" title bar. + +903 +00:44:02,210 --> 00:44:07,210 +Let's go ahead and make a +ZStack that has that title, + +904 +00:44:07,550 --> 00:44:11,670 +and then also has an +HStack, which has a Spacer + +905 +00:44:11,670 --> 00:44:14,197 +to move the Button all +the way over to the right. + +906 +00:44:14,197 --> 00:44:16,160 +And then has a Button. + +907 +00:44:16,160 --> 00:44:17,760 +And the Button, we'll +talk about the action + +908 +00:44:17,760 --> 00:44:18,877 +in a second here. + +909 +00:44:18,877 --> 00:44:23,293 +And the label we'll have it +be Text for the word "Done". + +910 +00:44:25,130 --> 00:44:27,170 +And we'll put some padding +on this one as well + +911 +00:44:27,170 --> 00:44:30,233 +just to make sure it's +got the room it needs. + +912 +00:44:32,246 --> 00:44:33,380 +Let's take a look to see +what that looks like. + +913 +00:44:33,380 --> 00:44:36,380 +So I've got a ZStack, so +I'm laying this on top of + +914 +00:44:36,380 --> 00:44:40,453 +this thing where the Button +is spaced out to the right. + +915 +00:44:43,120 --> 00:44:45,360 +Oh yeah, looking good, that "Done". + +916 +00:44:45,360 --> 00:44:47,740 +So clicking "Done" nothing is happening + +917 +00:44:47,740 --> 00:44:49,490 +'cause we didn't put +anything in our action. + +918 +00:44:49,490 --> 00:44:52,860 +So what are we gonna do when +we touch this "Done" Button + +919 +00:44:52,860 --> 00:44:54,563 +to make this whoop go away? + +920 +00:44:56,020 --> 00:44:58,200 +Very straightforward to do here, + +921 +00:44:58,200 --> 00:45:03,200 +in Button we are going to have +to have some indication here, + +922 +00:45:03,560 --> 00:45:06,923 +set some Bool that says whether +this is currently showing. + +923 +00:45:06,923 --> 00:45:11,740 +I'll call that isShowing equals false. + +924 +00:45:11,740 --> 00:45:14,570 +And this isShowing is gonna be similar, + +925 +00:45:14,570 --> 00:45:17,750 +in fact very similar to +this showPalette over here + +926 +00:45:17,750 --> 00:45:19,870 +that determines whether this is showing, + +927 +00:45:19,870 --> 00:45:22,820 +in fact, it is exactly this boolean. + +928 +00:45:22,820 --> 00:45:23,870 +This boolean is what makes + +929 +00:45:23,870 --> 00:45:25,800 +this sheet appear in the first place. + +930 +00:45:25,800 --> 00:45:29,760 +So if somehow this +isShowing could set this, + +931 +00:45:29,760 --> 00:45:32,350 +then it would make this go away. + +932 +00:45:32,350 --> 00:45:36,410 +And we know how to make +this be hooked up to this. + +933 +00:45:36,410 --> 00:45:37,800 +That's what Bindings are for. + +934 +00:45:37,800 --> 00:45:40,420 +So let's make another Binding here, + +935 +00:45:40,420 --> 00:45:44,210 +isShowing just going to be a Bool. + +936 +00:45:45,264 --> 00:45:49,490 +And we wanna bind to this +isShowing up to this one up here. + +937 +00:45:49,490 --> 00:45:52,240 +So just like we bound the chosenPalette, + +938 +00:45:52,240 --> 00:45:56,013 +using this Binding right here, +we're gonna bind isShowing + +939 +00:45:57,950 --> 00:46:02,170 +using this showPaletteEditor here. + +940 +00:46:02,170 --> 00:46:05,020 +This is how we make +these things come and go, + +941 +00:46:05,020 --> 00:46:07,020 +we share a Bool. + +942 +00:46:07,020 --> 00:46:10,230 +It might be an Identifiable in some cases + +943 +00:46:10,230 --> 00:46:13,500 +with some SwiftUI, but +it's often just a Bool + +944 +00:46:13,500 --> 00:46:15,993 +that says whether this thing is showing. + +945 +00:46:17,170 --> 00:46:18,573 +See if this works. + +946 +00:46:21,557 --> 00:46:24,310 +Here we go at this and boop, gone. + +947 +00:46:25,452 --> 00:46:26,777 +And bloop it's back. + +948 +00:46:26,777 --> 00:46:30,240 +And all we're doing when I +click this, when I click this + +949 +00:46:30,240 --> 00:46:35,230 +is setting this showPaletteEditor State. + +950 +00:46:35,230 --> 00:46:37,310 +Here's the setting it to true. + +951 +00:46:37,310 --> 00:46:39,430 +And here is setting it to false + +952 +00:46:39,430 --> 00:46:42,503 +inside this other View through a Binding. + +953 +00:46:43,860 --> 00:46:47,570 +Now, we've been doing a lot +of work with this on the iPad + +954 +00:46:47,570 --> 00:46:50,900 +and this is our iPad work here. + +955 +00:46:50,900 --> 00:46:52,690 +What about iPhone? + +956 +00:46:52,690 --> 00:46:54,930 +Is this all gonna work on the iPhone? + +957 +00:46:54,930 --> 00:46:57,730 +Let's take a look, let's see +if this works on an iPhone. + +958 +00:47:01,156 --> 00:47:02,313 +Look. + +959 +00:47:02,313 --> 00:47:05,900 +Woo-hoo, look at that, it works unchanged. + +960 +00:47:05,900 --> 00:47:08,580 +Here's that sheet, done, nice. + +961 +00:47:08,580 --> 00:47:11,357 +You can even swipe down to +get rid of this one as well. + +962 +00:47:11,357 --> 00:47:13,660 +And we've got this, we can edit it, + +963 +00:47:13,660 --> 00:47:18,223 +let's go change this to be activity stuff. + +964 +00:47:20,720 --> 00:47:22,570 +Activity stuff, very good. + +965 +00:47:22,570 --> 00:47:24,200 +We can add emojis. + +966 +00:47:24,200 --> 00:47:25,793 +Let's go add an emoji here. + +967 +00:47:26,650 --> 00:47:29,800 +Now, when I clicked on this to edit it, + +968 +00:47:29,800 --> 00:47:32,870 +it wants me to use the +hardware keyboard and type. + +969 +00:47:32,870 --> 00:47:34,960 +So one thing you have to be careful about + +970 +00:47:34,960 --> 00:47:38,070 +when you're working on +your app in a simulator + +971 +00:47:38,070 --> 00:47:40,340 +is whether you have the +hardware keyboard on + +972 +00:47:40,340 --> 00:47:43,310 +and you control that in the +simulator with this IO menu. + +973 +00:47:43,310 --> 00:47:45,130 +You see it's this keyboard right here. + +974 +00:47:45,130 --> 00:47:47,290 +And right now I have a +hardware keyboard connected. + +975 +00:47:47,290 --> 00:47:49,230 +If I disconnect the hardware keyboard, + +976 +00:47:49,230 --> 00:47:52,150 +then I'll get the keyboard +that your actual users + +977 +00:47:52,150 --> 00:47:53,260 +are gonna have to make, + +978 +00:47:53,260 --> 00:47:56,330 +which I really recommend you use this + +979 +00:47:56,330 --> 00:48:00,570 +because you're putting yourself +in the shoes of your users + +980 +00:48:00,570 --> 00:48:02,760 +when you use this versus +typing on your keyboard. + +981 +00:48:02,760 --> 00:48:04,300 +They don't, some of them might have + +982 +00:48:04,300 --> 00:48:06,570 +a Hardware Keyboard connected +with Bluetooth or something, + +983 +00:48:06,570 --> 00:48:09,560 +but 99% of them are gonna +have to type in here as well, + +984 +00:48:09,560 --> 00:48:14,560 +so it helps you make sure that +your UI is actually usable + +985 +00:48:14,750 --> 00:48:16,793 +and not relying on typing too much. + +986 +00:48:17,750 --> 00:48:21,137 +So to add soccer we're +gonna click it right there. + +987 +00:48:21,137 --> 00:48:23,720 +Oh, I'm double clicking +unnecessarily there. + +988 +00:48:23,720 --> 00:48:25,400 +We can see that works fine. + +989 +00:48:25,400 --> 00:48:29,380 +So if you put two of them in +there, it only puts one in + +990 +00:48:29,380 --> 00:48:32,030 +that's my little add +emoji that's doing that. + +991 +00:48:32,030 --> 00:48:33,437 +So it added the emojis there. + +992 +00:48:33,437 --> 00:48:35,610 +And I could remove the +bicyclist or whatever, + +993 +00:48:35,610 --> 00:48:36,517 +I'm editing this. + +994 +00:48:36,517 --> 00:48:38,943 +And when I hit "Done", yeah, okay. + +995 +00:48:38,943 --> 00:48:40,843 +I think there's no bicyclist in there. + +996 +00:48:42,490 --> 00:48:44,060 +Got our new ones in there. + +997 +00:48:44,060 --> 00:48:47,620 +So this is working great +for iPhone right here. + +998 +00:48:47,620 --> 00:48:50,530 +Unfortunately, there's no way +to add a background image. + +999 +00:48:50,530 --> 00:48:53,550 +So that's a problem we're +gonna have to fix on iPhone. + +1000 +00:48:53,550 --> 00:48:56,730 +And also it's just about +getting to be time here + +1001 +00:48:56,730 --> 00:48:59,010 +to be able to have multiple documents. + +1002 +00:48:59,010 --> 00:49:02,600 +By now we always just have +this one untitled document + +1003 +00:49:02,600 --> 00:49:05,310 +that we're editing, and +that's true on iPad as well. + +1004 +00:49:05,310 --> 00:49:09,030 +So our next step is going to +be able to add some UI here + +1005 +00:49:09,030 --> 00:49:12,250 +to have a list of documents, +different EmojiArtDocuments + +1006 +00:49:12,250 --> 00:49:13,430 +that we can click on, + +1007 +00:49:13,430 --> 00:49:16,023 +and it'll show us each of the documents. + +1008 +00:49:17,120 --> 00:49:20,790 +And this is gonna allow +us to learn something more + +1009 +00:49:20,790 --> 00:49:24,460 +in SwiftUI, which is how +to have multiple ViewModels + +1010 +00:49:24,460 --> 00:49:25,530 +in your app. + +1011 +00:49:25,530 --> 00:49:27,310 +Because right now we have a ViewModel + +1012 +00:49:27,310 --> 00:49:29,500 +that represents an EmojiArtDocument. + +1013 +00:49:29,500 --> 00:49:30,500 +That's great. + +1014 +00:49:30,500 --> 00:49:33,560 +We're gonna need a new +ViewModel, which represents + +1015 +00:49:33,560 --> 00:49:36,863 +a bunch of EmojiArtDocuments +in storage somewhere. + +1016 +00:49:38,160 --> 00:49:42,240 +So let's dive into this +by creating our ViewModel + +1017 +00:49:42,240 --> 00:49:45,430 +for a store of the EmojiArtDocuments, + +1018 +00:49:45,430 --> 00:49:47,290 +stored EmojiArtDocuments. + +1019 +00:49:47,290 --> 00:49:50,940 +Now, I, we've already seen +how to create ViewModels, + +1020 +00:49:50,940 --> 00:49:52,810 +it would be a little bit +repetitive to go do that. + +1021 +00:49:52,810 --> 00:49:56,490 +So I actually created my +EmojiArtDocument store here. + +1022 +00:49:56,490 --> 00:49:59,490 +We're gonna drag it in +and take a look at it. + +1023 +00:49:59,490 --> 00:50:01,040 +Copy it in. + +1024 +00:50:01,040 --> 00:50:05,660 +It's kind of the world's simplest +little storage thing here. + +1025 +00:50:05,660 --> 00:50:08,730 +But notice that it is a ViewModel class + +1026 +00:50:08,730 --> 00:50:10,740 +and ObservableObject. + +1027 +00:50:10,740 --> 00:50:12,690 +And this ViewModel has a name. + +1028 +00:50:12,690 --> 00:50:14,580 +So this is like the name of the store, + +1029 +00:50:14,580 --> 00:50:16,550 +we'll probably call it our EmojiArtStore + +1030 +00:50:16,550 --> 00:50:17,610 +or something like that. + +1031 +00:50:17,610 --> 00:50:19,230 +So this is where the things are stored. + +1032 +00:50:19,230 --> 00:50:20,500 +But then it also has the name + +1033 +00:50:20,500 --> 00:50:22,130 +for all the documents in the store. + +1034 +00:50:22,130 --> 00:50:24,290 +You can get the name of the document, + +1035 +00:50:24,290 --> 00:50:26,330 +see, this is just an EmojiArtDocument. + +1036 +00:50:26,330 --> 00:50:28,070 +This is our other ViewModel. + +1037 +00:50:28,070 --> 00:50:29,860 +So in a way, this is a ViewModel + +1038 +00:50:29,860 --> 00:50:34,860 +that has other ViewModels +as part of its content here. + +1039 +00:50:34,920 --> 00:50:37,610 +But you can set a name for +a document right down here. + +1040 +00:50:37,610 --> 00:50:39,910 +You can get all the documents +that we have names for, + +1041 +00:50:39,910 --> 00:50:41,340 +which is nice. + +1042 +00:50:41,340 --> 00:50:43,860 +You can add documents, the title or not + +1043 +00:50:43,860 --> 00:50:46,730 +it'll use "Untitled" if +you don't specify a name. + +1044 +00:50:46,730 --> 00:50:48,680 +And you can remove documents down here. + +1045 +00:50:49,750 --> 00:50:52,710 +Believe it or not, this +whole store, this whole thing + +1046 +00:50:52,710 --> 00:50:55,530 +only has one var that's +actually doing any storage. + +1047 +00:50:55,530 --> 00:50:57,690 +It's a published var, of +course, because when it changes + +1048 +00:50:57,690 --> 00:51:00,620 +we are an ObservableObject, +we're a ViewModel, + +1049 +00:51:00,620 --> 00:51:02,510 +we want our Views to find out. + +1050 +00:51:02,510 --> 00:51:06,560 +And this store is just a +Dictionary with EmojiArtDocuments + +1051 +00:51:06,560 --> 00:51:11,130 +as the keys and their names +of the document as a String. + +1052 +00:51:11,130 --> 00:51:14,550 +That's it, that is the +entirety of the storage + +1053 +00:51:14,550 --> 00:51:16,197 +in this ViewModel. + +1054 +00:51:16,197 --> 00:51:17,360 +And that's really all we need, + +1055 +00:51:17,360 --> 00:51:20,010 +we just need the document names that's, + +1056 +00:51:20,010 --> 00:51:22,700 +we can access them out of our store. + +1057 +00:51:22,700 --> 00:51:25,050 +By the way, it's very +common to have ViewModels + +1058 +00:51:25,050 --> 00:51:29,080 +that are essentially stores, +storage places for things. + +1059 +00:51:29,080 --> 00:51:31,180 +Our ViewModel that we've had for Memorize + +1060 +00:51:31,180 --> 00:51:35,850 +and that you had for Set are +really more logic-oriented. + +1061 +00:51:35,850 --> 00:51:38,360 +This is really not a lot of logic here. + +1062 +00:51:38,360 --> 00:51:40,380 +I guess naming these +things is kind of logic, + +1063 +00:51:40,380 --> 00:51:42,930 +but mostly it's just storing things. + +1064 +00:51:42,930 --> 00:51:44,060 +So you'll see a lot of ViewModels + +1065 +00:51:44,060 --> 00:51:46,493 +that have the word store in their name. + +1066 +00:51:47,890 --> 00:51:49,820 +Now, I've done a couple of things here, + +1067 +00:51:49,820 --> 00:51:54,370 +is I've used the Publisher +stuff that we know about + +1068 +00:51:54,370 --> 00:51:57,270 +to have it autosave into UserDefaults. + +1069 +00:51:57,270 --> 00:51:59,450 +Again, UserDefaults is +the only storage mechanism + +1070 +00:51:59,450 --> 00:52:02,140 +we know so far, so I'm +having to use UserDefault. + +1071 +00:52:02,140 --> 00:52:04,190 +I wouldn't store these documents + +1072 +00:52:04,190 --> 00:52:07,620 +in UserDefaults in the real +world but it's simple to do. + +1073 +00:52:07,620 --> 00:52:09,740 +One thing about storing +things in UserDefault + +1074 +00:52:09,740 --> 00:52:13,230 +is we know that UserDefaults +only stores property lists. + +1075 +00:52:13,230 --> 00:52:16,330 +And this is most certainly +not a property list + +1076 +00:52:16,330 --> 00:52:20,690 +because this is not one +of the prescribed types, + +1077 +00:52:20,690 --> 00:52:23,503 +String and Data, it's +none of those things. + +1078 +00:52:23,503 --> 00:52:25,850 +It's its own custom class. + +1079 +00:52:25,850 --> 00:52:28,610 +So I had to write a little +bit of code down here, + +1080 +00:52:28,610 --> 00:52:30,620 +I put it as an extension to Dictionary + +1081 +00:52:30,620 --> 00:52:35,430 +that converts this Dictionary +to a property list and back. + +1082 +00:52:35,430 --> 00:52:37,097 +So this gets it as a property list + +1083 +00:52:37,097 --> 00:52:39,350 +and this creates from a property list. + +1084 +00:52:39,350 --> 00:52:42,530 +That way, I could have +UserDefaults set object forKey + +1085 +00:52:42,530 --> 00:52:46,330 +and set, and get the object forKey + +1086 +00:52:46,330 --> 00:52:49,253 +and set the object for +key as a property list. + +1087 +00:52:50,950 --> 00:52:53,430 +Now, and you can look at +that later how I did that + +1088 +00:52:53,430 --> 00:52:55,470 +it's kinda cool. + +1089 +00:52:55,470 --> 00:52:57,960 +But not super important, because again, + +1090 +00:52:57,960 --> 00:53:00,530 +we're talking about interfacing +with an old API here + +1091 +00:53:00,530 --> 00:53:02,880 +in UserDefaults, so it's not +super important to understand + +1092 +00:53:02,880 --> 00:53:03,920 +what's going on in here. + +1093 +00:53:03,920 --> 00:53:07,160 +But we're using this as +thing that I talked about, + +1094 +00:53:07,160 --> 00:53:10,983 +and we're using Any, so this +is really kinda old stuff. + +1095 +00:53:11,980 --> 00:53:14,930 +Anyway, you can see I have a +lot of red here a lot of error. + +1096 +00:53:14,930 --> 00:53:16,410 +And it's mostly this error + +1097 +00:53:16,410 --> 00:53:17,787 +that's causing the problem right here. + +1098 +00:53:17,787 --> 00:53:21,497 +"Generic struct Dictionary +requires that EmojiArtDocuments + +1099 +00:53:21,497 --> 00:53:23,410 +"conform to Hashable." + +1100 +00:53:23,410 --> 00:53:25,880 +Anytime you wanna be +the key of a Dictionary, + +1101 +00:53:25,880 --> 00:53:27,540 +you have to be Hashable. + +1102 +00:53:27,540 --> 00:53:29,970 +Now we've seen this +Hashable protocol before, + +1103 +00:53:29,970 --> 00:53:31,347 +we didn't see how to implement it, + +1104 +00:53:31,347 --> 00:53:32,970 +but we saw that it exists, + +1105 +00:53:32,970 --> 00:53:35,720 +it was over here in our Grid, okay? + +1106 +00:53:35,720 --> 00:53:39,680 +ForEach is essentially +creating up a little Dictionary + +1107 +00:53:39,680 --> 00:53:42,800 +with these items, and all +these Views as their values + +1108 +00:53:42,800 --> 00:53:44,040 +and so that's why we had to say + +1109 +00:53:44,040 --> 00:53:48,300 +that that ID into this thing, +it's gotta be a Hashable thing + +1110 +00:53:48,300 --> 00:53:50,580 +so that ForEach can +put 'em in a Dictionary + +1111 +00:53:50,580 --> 00:53:52,500 +or whatever it's doing inside there. + +1112 +00:53:52,500 --> 00:53:54,590 +So we have seen Hashable before, + +1113 +00:53:54,590 --> 00:53:57,330 +but now we're gonna have to +actually implement Hashable + +1114 +00:53:57,330 --> 00:53:59,250 +in EmojiArtDocument + +1115 +00:53:59,250 --> 00:54:02,890 +because we want EmojiArtDocument +itself to be Hashable. + +1116 +00:54:02,890 --> 00:54:05,300 +So here's EmojiArtDocument, +it's a ViewModel, + +1117 +00:54:05,300 --> 00:54:09,553 +it's a class and our requirement +is that it be Hashable. + +1118 +00:54:10,690 --> 00:54:13,800 +Now, what is in this Hashable protocol? + +1119 +00:54:13,800 --> 00:54:16,620 +It only has one function in it. + +1120 +00:54:16,620 --> 00:54:19,670 +This function is called hash +as you might've guessed. + +1121 +00:54:19,670 --> 00:54:23,670 +And you can see it +right there into hasher. + +1122 +00:54:23,670 --> 00:54:26,560 +So this hasher is just an +object that's given to you + +1123 +00:54:26,560 --> 00:54:28,390 +when you're being asked to hash. + +1124 +00:54:28,390 --> 00:54:31,270 +And it only really has one function in it. + +1125 +00:54:31,270 --> 00:54:36,270 +This hasher has combine, and +you give it something here, + +1126 +00:54:37,600 --> 00:54:41,090 +that is itself Hashable, and it combines + +1127 +00:54:41,090 --> 00:54:45,850 +possibly multiple things +inside your object + +1128 +00:54:45,850 --> 00:54:47,310 +to make it Hashable. + +1129 +00:54:47,310 --> 00:54:48,960 +So we're combining Hashable things + +1130 +00:54:48,960 --> 00:54:50,950 +to make something Hashable. + +1131 +00:54:50,950 --> 00:54:53,410 +Now, what could we combine here? + +1132 +00:54:53,410 --> 00:54:56,900 +What makes us unique +enough to be hashed, right? + +1133 +00:54:56,900 --> 00:54:58,683 +To be put into a hash table? + +1134 +00:54:59,670 --> 00:55:02,630 +Well, of course our +EmojiArtDocument itself + +1135 +00:55:02,630 --> 00:55:06,510 +is quite unique, it's got emojis +in the background in there. + +1136 +00:55:06,510 --> 00:55:08,870 +So we could make this Hashable + +1137 +00:55:08,870 --> 00:55:11,143 +and then combine here have emojiArt. + +1138 +00:55:12,370 --> 00:55:14,820 +But it's a little bit overkill to do that, + +1139 +00:55:14,820 --> 00:55:16,750 +and it actually might not be that good + +1140 +00:55:16,750 --> 00:55:18,690 +in that every time we change our document, + +1141 +00:55:18,690 --> 00:55:21,211 +our hash is gonna change. + +1142 +00:55:21,211 --> 00:55:24,810 +It'd be a lot better if we +had some unique identifier + +1143 +00:55:24,810 --> 00:55:26,850 +that we could hash in here. + +1144 +00:55:26,850 --> 00:55:27,850 +So I'm gonna do that. + +1145 +00:55:27,850 --> 00:55:30,870 +I'm gonna create a little +unique identifier here, + +1146 +00:55:30,870 --> 00:55:32,593 +I'm gonna call it id. + +1147 +00:55:33,460 --> 00:55:35,850 +And I'm gonna make it be a UUID. + +1148 +00:55:35,850 --> 00:55:39,280 +Now, I mentioned UUID before, +this is a little struct + +1149 +00:55:39,280 --> 00:55:42,120 +that generates a unique thing. + +1150 +00:55:42,120 --> 00:55:45,610 +That's really all it's for +is to create a unique thing. + +1151 +00:55:45,610 --> 00:55:48,930 +Now the reason I called my +little unique identifier id + +1152 +00:55:48,930 --> 00:55:52,830 +is because now I can also +say that I'm Identifiable, + +1153 +00:55:52,830 --> 00:55:54,800 +which might be nice someday. + +1154 +00:55:54,800 --> 00:55:57,130 +Why call this something else, + +1155 +00:55:57,130 --> 00:55:59,640 +when it is a unique Identifiable thing? + +1156 +00:55:59,640 --> 00:56:02,730 +Might as well get +Identifiable for free here. + +1157 +00:56:02,730 --> 00:56:04,650 +So I'm just gonna combine +that and hash that. + +1158 +00:56:04,650 --> 00:56:07,730 +So my hashing is basically +going to be the hashing of this. + +1159 +00:56:07,730 --> 00:56:10,713 +Luckily, your UUID is a +Hashable thing itself. + +1160 +00:56:11,580 --> 00:56:13,150 +That seems like that should be enough + +1161 +00:56:13,150 --> 00:56:15,403 +but we got more complaints up here. + +1162 +00:56:15,403 --> 00:56:19,180 +"EmojiArtDocument does +not conform to Equatable." + +1163 +00:56:19,180 --> 00:56:23,320 +So to be Hashable, you also +have to implement Equatable. + +1164 +00:56:23,320 --> 00:56:25,840 +In other words, there's an +inheritance relationship + +1165 +00:56:25,840 --> 00:56:28,600 +between Hashable and Equatable. + +1166 +00:56:28,600 --> 00:56:30,170 +Those two protocols. + +1167 +00:56:30,170 --> 00:56:32,820 +So what is in the Equatable protocol? + +1168 +00:56:32,820 --> 00:56:34,750 +I'm actually gonna use "Fix" right here + +1169 +00:56:34,750 --> 00:56:39,000 +to give this protocol stubs +briefly show us what's in there. + +1170 +00:56:39,000 --> 00:56:41,410 +Boop and it's just this one function. + +1171 +00:56:41,410 --> 00:56:43,690 +It totally makes sense +when you think about it. + +1172 +00:56:43,690 --> 00:56:47,570 +It's a static function +on the type called == + +1173 +00:56:47,570 --> 00:56:50,950 +remember that Swift can use any, + +1174 +00:56:50,950 --> 00:56:53,340 +it could use emoji as +the name of a function. + +1175 +00:56:53,340 --> 00:56:57,080 +So == is just a perfectly reasonable + +1176 +00:56:57,080 --> 00:56:58,360 +name of a function. + +1177 +00:56:58,360 --> 00:57:00,550 +That's all this is, the +name of this function. + +1178 +00:57:00,550 --> 00:57:02,560 +It takes two arguments, a left hand side + +1179 +00:57:02,560 --> 00:57:03,870 +and a right hand side. + +1180 +00:57:03,870 --> 00:57:06,650 +Both of which, of course, +are EmojiArtDocuments, + +1181 +00:57:06,650 --> 00:57:08,070 +and it's returning a Bool, + +1182 +00:57:08,070 --> 00:57:10,820 +whether these two things are equal. + +1183 +00:57:10,820 --> 00:57:12,390 +So for us, that's really easy. + +1184 +00:57:12,390 --> 00:57:16,100 +Left hand side.id equals +right hand side.id. + +1185 +00:57:16,100 --> 00:57:18,530 +If those IDs are the same, this unique ID, + +1186 +00:57:18,530 --> 00:57:20,760 +then this must be the same document. + +1187 +00:57:20,760 --> 00:57:22,370 +But a word of warning here, + +1188 +00:57:22,370 --> 00:57:24,440 +this strategy is really only gonna work + +1189 +00:57:24,440 --> 00:57:27,100 +for a reference type for a class, + +1190 +00:57:27,100 --> 00:57:30,890 +because we're all seeing the +same version of it in the heap. + +1191 +00:57:30,890 --> 00:57:33,640 +For struct, it's a value type, + +1192 +00:57:33,640 --> 00:57:35,740 +we're copying it around all the time, + +1193 +00:57:35,740 --> 00:57:37,270 +we actually need to be able to see + +1194 +00:57:37,270 --> 00:57:40,830 +is this copy == to this other copy? + +1195 +00:57:40,830 --> 00:57:43,320 +And we wouldn't wanna +do that just by the ID. + +1196 +00:57:43,320 --> 00:57:45,750 +That's what Identifiable is for, + +1197 +00:57:45,750 --> 00:57:48,080 +we actually need to check and see if + +1198 +00:57:48,080 --> 00:57:50,360 +all the vars are equal to each other. + +1199 +00:57:50,360 --> 00:57:51,440 +And same thing for hashing, + +1200 +00:57:51,440 --> 00:57:54,440 +we wanna hash all the vars in there. + +1201 +00:57:54,440 --> 00:57:56,590 +And in fact, that's the +default implementation + +1202 +00:57:56,590 --> 00:58:01,590 +of Hashable in Swift is for +structs to check all the vars. + +1203 +00:58:02,690 --> 00:58:05,420 +And we do this in our EmojiArt Model, + +1204 +00:58:05,420 --> 00:58:07,750 +we have a little sub-struct +there, the Emoji, + +1205 +00:58:07,750 --> 00:58:11,300 +and we marked it Hashable and +Hashable includes Equatable. + +1206 +00:58:11,300 --> 00:58:13,840 +And yeah, we didn't have to do == or hash, + +1207 +00:58:13,840 --> 00:58:16,650 +we just used the default +version that we got from Swift, + +1208 +00:58:16,650 --> 00:58:18,293 +which checks all the variables. + +1209 +00:58:19,420 --> 00:58:22,000 +But for a class, this is a nice, really + +1210 +00:58:22,000 --> 00:58:25,580 +very, very simple way to +get equality and hashability + +1211 +00:58:25,580 --> 00:58:29,120 +and identity all in very simple code. + +1212 +00:58:29,120 --> 00:58:32,870 +And we can use this little bit +of code for one more thing, + +1213 +00:58:32,870 --> 00:58:36,270 +which is that right now we +store our EmojiArtDocuments + +1214 +00:58:36,270 --> 00:58:40,560 +in UserDefaults, but we store +them as this "Untitled", + +1215 +00:58:40,560 --> 00:58:42,810 +so they're not each +separately being stored + +1216 +00:58:42,810 --> 00:58:43,920 +as something else. + +1217 +00:58:43,920 --> 00:58:46,010 +But now that we have a unique ID, + +1218 +00:58:46,010 --> 00:58:48,280 +we can still store them in default, + +1219 +00:58:48,280 --> 00:58:51,283 +but instead of under +"Untitled", with that unique ID. + +1220 +00:58:52,550 --> 00:58:56,500 +So to do that, I'm going to +have my init take the id, + +1221 +00:58:56,500 --> 00:59:01,200 +the UUID for that +particular EmojiArtDocument, + +1222 +00:59:01,200 --> 00:59:02,330 +because if you give me an ID, + +1223 +00:59:02,330 --> 00:59:05,203 +I'll go look it up in +UserDefaults and get it for you. + +1224 +00:59:06,460 --> 00:59:09,997 +And I could have it default +to creating a random UUID + +1225 +00:59:10,916 --> 00:59:13,810 +then I wouldn't even need to +do this initialization here. + +1226 +00:59:13,810 --> 00:59:17,100 +I could just have this be let ID UUID + +1227 +00:59:17,100 --> 00:59:20,273 +and then say self.id equals this id. + +1228 +00:59:21,360 --> 00:59:24,530 +This defaulting, we haven't +done it much in our demos, + +1229 +00:59:24,530 --> 00:59:26,400 +but hopefully you know about that, + +1230 +00:59:26,400 --> 00:59:28,640 +that you can have a something default, + +1231 +00:59:28,640 --> 00:59:31,880 +and then someone could call +my init with no arguments, + +1232 +00:59:31,880 --> 00:59:34,830 +and it would get some new identifier, + +1233 +00:59:34,830 --> 00:59:37,150 +which makes sense if I +create an Emoji Art with, + +1234 +00:59:37,150 --> 00:59:39,350 +an EmojiArtDocument with no arguments + +1235 +00:59:39,350 --> 00:59:42,340 +I want it to get its own unique ID. + +1236 +00:59:42,340 --> 00:59:43,290 +I'm gonna show you another way + +1237 +00:59:43,290 --> 00:59:46,320 +that you'll often see +this defaulting done, + +1238 +00:59:46,320 --> 00:59:48,540 +which is instead of setting +equal, so I'm thinking, + +1239 +00:59:48,540 --> 00:59:52,090 +it'll make it an Optional +and set it equal to nil, + +1240 +00:59:52,090 --> 00:59:54,623 +and then do this defaulting right here. + +1241 +00:59:55,790 --> 00:59:58,130 +Now, why would we do it this way? + +1242 +00:59:58,130 --> 01:00:00,900 +Why would we make this an Optional? + +1243 +01:00:00,900 --> 01:00:04,360 +Because now we can call +this init with no arguments + +1244 +01:00:04,360 --> 01:00:09,360 +or we can call it with a UUID, +or we can call it with nil. + +1245 +01:00:09,390 --> 01:00:11,440 +So now there's a little more flexibility + +1246 +01:00:11,440 --> 01:00:15,620 +in how we create this EmojiArtDocument. + +1247 +01:00:15,620 --> 01:00:16,880 +Totally flexibility, + +1248 +01:00:16,880 --> 01:00:18,780 +it's really no other difference otherwise + +1249 +01:00:18,780 --> 01:00:21,980 +but I mentioned this, because +you're gonna see this in Swift + +1250 +01:00:21,980 --> 01:00:24,720 +where there are functions +that seem to take an argument + +1251 +01:00:24,720 --> 01:00:26,600 +that isn't Optional, that defaults to nil, + +1252 +01:00:26,600 --> 01:00:27,730 +and you're like, why does it do that? + +1253 +01:00:27,730 --> 01:00:29,270 +Well, this is all it's doing. + +1254 +01:00:29,270 --> 01:00:33,160 +It wants to keep whatever +it defaults it to internal. + +1255 +01:00:33,160 --> 01:00:35,590 +It doesn't want it to be made explicit, + +1256 +01:00:35,590 --> 01:00:38,430 +and so that people can +see what the default is + +1257 +01:00:38,430 --> 01:00:42,120 +if for some reason don't want +that to be public information. + +1258 +01:00:42,120 --> 01:00:43,183 +It's perfectly fine. + +1259 +01:00:44,380 --> 01:00:47,600 +So now instead of storing +this as "Untitled", right? + +1260 +01:00:47,600 --> 01:00:49,740 +This "Untitled", let's get rid of that. + +1261 +01:00:49,740 --> 01:00:54,000 +Instead, I'm just gonna have +a little let here defaultsKey. + +1262 +01:00:54,000 --> 01:00:57,173 +And we're gonna have this +be EmojiArtDocument., + +1263 +01:00:59,340 --> 01:01:03,470 +and I'm gonna use this little +embedding of Strings here + +1264 +01:01:03,470 --> 01:01:07,140 +to put my ID in there as a String. + +1265 +01:01:07,140 --> 01:01:10,510 +And it has a nice +function here, uuidString + +1266 +01:01:10,510 --> 01:01:12,720 +that will give it to you that way. + +1267 +01:01:12,720 --> 01:01:14,270 +So this is the default key I'm gonna use + +1268 +01:01:14,270 --> 01:01:15,843 +instead of this "Untitled", + +1269 +01:01:17,650 --> 01:01:22,513 +in both when I'm getting it +there and when I am saving it. + +1270 +01:01:23,460 --> 01:01:25,890 +So now, I've made my documents + +1271 +01:01:25,890 --> 01:01:28,603 +persist always in UserDefaults. + +1272 +01:01:29,750 --> 01:01:31,830 +So that's it for our store. + +1273 +01:01:31,830 --> 01:01:34,050 +And we're gonna use this store right now + +1274 +01:01:34,050 --> 01:01:36,880 +as the ViewModel of a new +View that we're gonna build + +1275 +01:01:36,880 --> 01:01:39,170 +that let's us choose documents. + +1276 +01:01:39,170 --> 01:01:40,980 +So it's a document chooser. + +1277 +01:01:40,980 --> 01:01:44,053 +Let's go ahead in here and +create a new SwiftUI View. + +1278 +01:01:45,670 --> 01:01:47,940 +It is a SwiftUI View, this chooser. + +1279 +01:01:47,940 --> 01:01:50,180 +It's a list of documents, +but it is a View. + +1280 +01:01:50,180 --> 01:01:52,430 +I'm gonna call it my +EmojiArtDocumentChooser. + +1281 +01:01:54,720 --> 01:01:57,540 +I might be starting to regret +putting EmojiArtDocument + +1282 +01:01:57,540 --> 01:01:59,340 +in front of everything +here, but not really. + +1283 +01:01:59,340 --> 01:02:02,633 +It's nice to have good +clear names of things. + +1284 +01:02:03,800 --> 01:02:05,740 +So here is my chooser. + +1285 +01:02:05,740 --> 01:02:09,710 +And this chooser is essentially +going to have a store. + +1286 +01:02:09,710 --> 01:02:11,030 +And I'm gonna make the store be + +1287 +01:02:11,030 --> 01:02:12,943 +an EnvironmentObject as well. + +1288 +01:02:14,140 --> 01:02:16,370 +I could make this ObservedObject, + +1289 +01:02:16,370 --> 01:02:18,110 +but I'm just trying to mix it up here. + +1290 +01:02:18,110 --> 01:02:20,780 +I'm not really putting this in a popover + +1291 +01:02:20,780 --> 01:02:24,200 +or a sheet that would require +me to do EnvironmentObject. + +1292 +01:02:24,200 --> 01:02:27,260 +But it's pretty common +to use EnvironmentObject + +1293 +01:02:27,260 --> 01:02:29,307 +especially for a top level View like this + +1294 +01:02:29,307 --> 01:02:32,113 +that's going to be choosing +other Views, et cetera. + +1295 +01:02:33,610 --> 01:02:37,420 +So how do we take, get our list +of objects in our store here + +1296 +01:02:37,420 --> 01:02:39,010 +and display them in our body? + +1297 +01:02:39,010 --> 01:02:41,670 +We know exactly how to take +a list of something and show, + +1298 +01:02:41,670 --> 01:02:46,230 +we do a ForEach, and we're +going to do the store.documents. + +1299 +01:02:46,230 --> 01:02:48,340 +And now I'm awfully glad + +1300 +01:02:48,340 --> 01:02:51,690 +that I made EmojiArtDocument Identifiable + +1301 +01:02:51,690 --> 01:02:53,920 +because store.documents over here + +1302 +01:02:54,790 --> 01:02:57,010 +is an Array of EmojiArtDocument. + +1303 +01:02:57,010 --> 01:03:00,100 +Woo, this has to be +Identifiable for ForEach to work + +1304 +01:03:00,100 --> 01:03:02,910 +and woo we got it to be Identifiable + +1305 +01:03:02,910 --> 01:03:04,470 +by making this be called id. + +1306 +01:03:04,470 --> 01:03:05,723 +And of course, I knew I was gonna do that. + +1307 +01:03:05,723 --> 01:03:08,643 +But you can see the benefit +there of having done that. + +1308 +01:03:10,220 --> 01:03:11,820 +All right, so we've got our documents + +1309 +01:03:11,820 --> 01:03:15,000 +and for each document, I +just wanna create a View that + +1310 +01:03:15,000 --> 01:03:17,263 +kinda shows that document in the list. + +1311 +01:03:19,040 --> 01:03:23,130 +So we'll do that by just +doing a Text let's say, + +1312 +01:03:23,130 --> 01:03:27,080 +of the store's name for that document. + +1313 +01:03:27,080 --> 01:03:30,570 +So, it's just gonna be a list +of the names of the documents. + +1314 +01:03:30,570 --> 01:03:33,430 +Now, of course, we know +ForEach doesn't do layouts. + +1315 +01:03:33,430 --> 01:03:36,830 +So we have to put this +in an HStack or a VStack + +1316 +01:03:36,830 --> 01:03:39,220 +or a Grid or some kind of layout thing. + +1317 +01:03:39,220 --> 01:03:41,200 +And we're gonna learn a new one today. + +1318 +01:03:41,200 --> 01:03:44,090 +This one is called a List. + +1319 +01:03:44,090 --> 01:03:47,750 +So List, kind of like a VStack + +1320 +01:03:47,750 --> 01:03:49,730 +feels a little bit like a VStack, + +1321 +01:03:49,730 --> 01:03:51,020 +but it's much more powerful + +1322 +01:03:51,020 --> 01:03:53,270 +that it creates a big scrollable list + +1323 +01:03:53,270 --> 01:03:55,860 +with separators and all that stuff. + +1324 +01:03:55,860 --> 01:03:59,800 +And it looks just like in what +you've seen in other apps, + +1325 +01:03:59,800 --> 01:04:03,083 +what in the old UI kit +we called a TableView. + +1326 +01:04:04,490 --> 01:04:08,900 +Now, we have to pass, and we'll +see this in just a second, + +1327 +01:04:08,900 --> 01:04:11,190 +we have to pass our store in here. + +1328 +01:04:11,190 --> 01:04:13,270 +And also I want this document chooser. + +1329 +01:04:13,270 --> 01:04:15,003 +When I run my app right now, + +1330 +01:04:16,300 --> 01:04:18,630 +it's showing me an EmojiArtDocument. + +1331 +01:04:18,630 --> 01:04:20,810 +But I want it to show +this chooser instead. + +1332 +01:04:20,810 --> 01:04:23,370 +So I'm gonna have to go back +to my theme delegate here, + +1333 +01:04:23,370 --> 01:04:25,870 +and not do this EmojiArtDocumentView + +1334 +01:04:26,780 --> 01:04:29,783 +and instead do an EmojiArtDocumentChooser. + +1335 +01:04:32,190 --> 01:04:34,500 +And this takes no arguments, okay. + +1336 +01:04:34,500 --> 01:04:38,783 +But it does want you to +provide this EnvironmentObject, + +1337 +01:04:40,100 --> 01:04:41,800 +which has to be the store. + +1338 +01:04:41,800 --> 01:04:43,830 +So we're gonna have to create that store. + +1339 +01:04:43,830 --> 01:04:47,746 +I'm gonna say let store equal + +1340 +01:04:47,746 --> 01:04:51,504 +an EmojiArtDocumentStore. + +1341 +01:04:52,400 --> 01:04:54,000 +This happens to take a name + +1342 +01:04:54,000 --> 01:04:56,362 +so I'm gonna call mine "Emoji Art". + +1343 +01:04:56,362 --> 01:04:58,940 +That's gonna be the name +of this document store. + +1344 +01:04:58,940 --> 01:05:02,070 +Let's even put a couple +of documents in there. + +1345 +01:05:02,070 --> 01:05:03,120 +So store.addDocument. + +1346 +01:05:04,480 --> 01:05:09,480 +Maybe store.addDocument +named "Hello World". + +1347 +01:05:11,470 --> 01:05:13,540 +So all this stuff I'm +doing here addDocument + +1348 +01:05:13,540 --> 01:05:14,410 +and creating the store, + +1349 +01:05:14,410 --> 01:05:16,620 +that's all the stuff that's +in store here, right? + +1350 +01:05:16,620 --> 01:05:18,530 +Here's addDocument, creates that. + +1351 +01:05:18,530 --> 01:05:22,313 +Here's the document, +creating the document. + +1352 +01:05:23,270 --> 01:05:25,190 +Initializer is right here, right? + +1353 +01:05:25,190 --> 01:05:27,230 +Init named, I'm just creating this, + +1354 +01:05:27,230 --> 01:05:29,120 +I'm not doing anything special here, + +1355 +01:05:29,120 --> 01:05:31,220 +I'm just creating the store. + +1356 +01:05:31,220 --> 01:05:33,410 +And then I'm setting the +store as the environment + +1357 +01:05:33,410 --> 01:05:36,770 +for my chooser so that +my chooser has this store + +1358 +01:05:36,770 --> 01:05:39,027 +and it can go through +all the store's documents + +1359 +01:05:39,027 --> 01:05:40,070 +and show the names. + +1360 +01:05:40,070 --> 01:05:43,393 +And it's gonna do it in this List UI. + +1361 +01:05:43,393 --> 01:05:45,343 +So let's see what this List looks like. + +1362 +01:05:47,929 --> 01:05:50,250 +Woo-hoo, there we go, we've +got our two documents. + +1363 +01:05:50,250 --> 01:05:52,040 +Now, this is a scrollable list, + +1364 +01:05:52,040 --> 01:05:53,763 +so we can scroll it up and down. + +1365 +01:05:55,220 --> 01:05:57,830 +So this store itself is persistent. + +1366 +01:05:57,830 --> 01:06:01,920 +So if we go back to our +SceneDelegate over here, + +1367 +01:06:01,920 --> 01:06:05,573 +and delete these addDocuments and rerun, + +1368 +01:06:08,230 --> 01:06:11,200 +they'll stay in the list right there. + +1369 +01:06:11,200 --> 01:06:15,130 +Now, this is great, but +when we tap on these, + +1370 +01:06:15,130 --> 01:06:17,520 +it does not show us these documents, + +1371 +01:06:17,520 --> 01:06:20,350 +Hello World and Untitled, +it's not showing them to us. + +1372 +01:06:20,350 --> 01:06:22,340 +To make it so that clicking on things + +1373 +01:06:22,340 --> 01:06:26,730 +navigates to a different View +to show us those documents, + +1374 +01:06:26,730 --> 01:06:31,730 +we have to embed our List +right here in another View + +1375 +01:06:32,240 --> 01:06:34,193 +called a NavigationView. + +1376 +01:06:36,221 --> 01:06:39,910 +NavigationView, which +very often, almost always, + +1377 +01:06:39,910 --> 01:06:42,430 +for putting a List inside a navigation, + +1378 +01:06:42,430 --> 01:06:43,770 +is not absolutely required. + +1379 +01:06:43,770 --> 01:06:47,563 +Sometimes we might put a +Form in here, possibly. + +1380 +01:06:48,570 --> 01:06:50,530 +So our NavigationView has only changed + +1381 +01:06:50,530 --> 01:06:52,200 +our View a little bit here, + +1382 +01:06:52,200 --> 01:06:55,030 +but it's still not making +it so if we tap on these, + +1383 +01:06:55,030 --> 01:06:58,410 +I'm tapping on these, it's +not making any difference. + +1384 +01:06:58,410 --> 01:07:01,050 +That's because these are +just Texts right here, + +1385 +01:07:01,050 --> 01:07:04,930 +text when you tap on them, they +don't know how to navigate. + +1386 +01:07:04,930 --> 01:07:08,250 +So we're gonna wrap these also in a View + +1387 +01:07:08,250 --> 01:07:10,253 +called a NavigationLink. + +1388 +01:07:11,900 --> 01:07:16,340 +Now, NavigationLink has quite +a few ways to create it. + +1389 +01:07:16,340 --> 01:07:19,100 +But in all of them, there's +a very important argument + +1390 +01:07:19,100 --> 01:07:22,290 +you can see right here called destination. + +1391 +01:07:22,290 --> 01:07:25,740 +This destination is where +this link is gonna go + +1392 +01:07:25,740 --> 01:07:26,880 +when you tap on it. + +1393 +01:07:26,880 --> 01:07:31,880 +In other words, give me +a View to navigate to + +1394 +01:07:32,210 --> 01:07:33,900 +when I click on this. + +1395 +01:07:33,900 --> 01:07:36,210 +So in our case, the destination we want + +1396 +01:07:36,210 --> 01:07:39,520 +is we want an EmojiArtDocumentView + +1397 +01:07:39,520 --> 01:07:43,670 +that shows this document that +you just clicked on, right? + +1398 +01:07:43,670 --> 01:07:46,180 +We're in a ForEach, we've +got these documents. + +1399 +01:07:46,180 --> 01:07:49,093 +We wanna go to a document +View that shows this document. + +1400 +01:07:50,230 --> 01:07:53,330 +And now we put this Text inside + +1401 +01:07:53,330 --> 01:07:55,693 +the content of this NavigationLink View. + +1402 +01:07:56,780 --> 01:07:59,360 +This is how we make it so that things + +1403 +01:07:59,360 --> 01:08:02,023 +that are in our List are navigatable. + +1404 +01:08:03,080 --> 01:08:04,330 +Let's see that in action. + +1405 +01:08:06,300 --> 01:08:08,670 +All right, now notice +something has changed. + +1406 +01:08:08,670 --> 01:08:11,120 +Now there's a little +greater than sign here. + +1407 +01:08:11,120 --> 01:08:14,020 +That's letting the user +know if you tap on this, + +1408 +01:08:14,020 --> 01:08:15,650 +it's gonna go somewhere. + +1409 +01:08:15,650 --> 01:08:17,100 +And let's try. + +1410 +01:08:17,100 --> 01:08:20,123 +Whoop, there it is, look at that. + +1411 +01:08:20,123 --> 01:08:23,650 +All right, we have +different documents here. + +1412 +01:08:23,650 --> 01:08:26,860 +Now, this is all a little kinda blank + +1413 +01:08:26,860 --> 01:08:28,687 +and it's hard to tell what's going on. + +1414 +01:08:28,687 --> 01:08:32,360 +And the NavigationView +provides a lot of mechanism + +1415 +01:08:32,360 --> 01:08:35,440 +to make this all more +understandable to the user. + +1416 +01:08:35,440 --> 01:08:38,070 +For example, titles, we can put a title, + +1417 +01:08:38,070 --> 01:08:39,993 +that's what this kinda blank +space at the top here is. + +1418 +01:08:39,993 --> 01:08:43,650 +And we can put a title in +front of on top of this List, + +1419 +01:08:43,650 --> 01:08:45,930 +and we can also put a +different title if you want + +1420 +01:08:45,930 --> 01:08:48,670 +on top of this View right here. + +1421 +01:08:48,670 --> 01:08:50,390 +So when you're in a NavigationView, + +1422 +01:08:50,390 --> 01:08:51,760 +and you're navigating around, + +1423 +01:08:51,760 --> 01:08:54,050 +you can put titles on each one. + +1424 +01:08:54,050 --> 01:08:57,970 +You set this title on each +View that can appear here. + +1425 +01:08:57,970 --> 01:09:00,760 +So we're gonna set a title on this list, + +1426 +01:09:00,760 --> 01:09:02,070 +then we're gonna set a title + +1427 +01:09:02,070 --> 01:09:05,490 +on this EmojiArtDocument View. + +1428 +01:09:05,490 --> 01:09:06,930 +Let's do that. + +1429 +01:09:06,930 --> 01:09:09,430 +So here's the List, let's set its title. + +1430 +01:09:09,430 --> 01:09:14,020 +So when the List is showing, +the navigationBarTitle + +1431 +01:09:14,020 --> 01:09:17,610 +is going to be... how +about the store's name, + +1432 +01:09:17,610 --> 01:09:18,730 +the name of our store, + +1433 +01:09:18,730 --> 01:09:20,430 +because that's what this List is showing, + +1434 +01:09:20,430 --> 01:09:22,660 +it's showing all the +documents in this store. + +1435 +01:09:22,660 --> 01:09:23,980 +Let's do the store's name. + +1436 +01:09:23,980 --> 01:09:26,083 +Store name is just a var here, + +1437 +01:09:26,083 --> 01:09:28,330 +and the store keeps track of its name, + +1438 +01:09:28,330 --> 01:09:30,060 +nothing more than that. + +1439 +01:09:30,060 --> 01:09:34,490 +And then here's our +EmojiArtDocument View right here. + +1440 +01:09:34,490 --> 01:09:38,710 +Let's put a name on it as +well, navigationBarTitle. + +1441 +01:09:39,950 --> 01:09:44,950 +This is the store's +name for this document. + +1442 +01:09:45,480 --> 01:09:50,480 +Now, notice that I am putting +this bar title onto this View. + +1443 +01:09:51,810 --> 01:09:54,300 +This is the EmojiArtDocumentView + +1444 +01:09:54,300 --> 01:09:56,960 +that I show when I navigate +here, the destination. + +1445 +01:09:56,960 --> 01:09:58,980 +So when this View is showing, + +1446 +01:09:58,980 --> 01:10:01,199 +this is the title that we'll use, + +1447 +01:10:01,199 --> 01:10:03,589 +navigationBarTitle, you put it on the View + +1448 +01:10:03,589 --> 01:10:07,050 +that will be showing, +and this is what you get. + +1449 +01:10:08,640 --> 01:10:10,913 +Emoji Art, that's the name of our store. + +1450 +01:10:11,769 --> 01:10:13,560 +When we click, Hello World, + +1451 +01:10:13,560 --> 01:10:14,690 +that's the name of this document, right? + +1452 +01:10:14,690 --> 01:10:17,140 +This is the Hello World document, + +1453 +01:10:17,140 --> 01:10:19,170 +this is the Untitled document. + +1454 +01:10:19,170 --> 01:10:20,970 +Now there's other things +that we can put here + +1455 +01:10:20,970 --> 01:10:23,990 +besides a title, we can +actually put some buttons. + +1456 +01:10:23,990 --> 01:10:25,070 +Like it would be nice to have + +1457 +01:10:25,070 --> 01:10:27,170 +a little buttons at the top here, + +1458 +01:10:27,170 --> 01:10:29,930 +maybe a button that +adds another Emoji Art, + +1459 +01:10:29,930 --> 01:10:32,200 +creates a new untitled document. + +1460 +01:10:32,200 --> 01:10:34,350 +So I'm gonna put a little +plus button right here + +1461 +01:10:34,350 --> 01:10:36,565 +that does exactly that. + +1462 +01:10:36,565 --> 01:10:37,497 +Go right down here. + +1463 +01:10:37,497 --> 01:10:40,620 +And this is on the, this Button +is only gonna be available + +1464 +01:10:40,620 --> 01:10:42,790 +when this List is showing not over here + +1465 +01:10:42,790 --> 01:10:44,853 +when the EmojiArtDocumentView is showing, + +1466 +01:10:44,853 --> 01:10:46,190 +only when the List is showing, + +1467 +01:10:46,190 --> 01:10:49,660 +navigationBarItems, this is called. + +1468 +01:10:49,660 --> 01:10:51,200 +And you can have leading and trailing. + +1469 +01:10:51,200 --> 01:10:53,570 +I'll put this on the leading side. + +1470 +01:10:53,570 --> 01:10:54,823 +And it's just a Button. + +1471 +01:10:55,954 --> 01:10:57,430 +You know how to do Buttons. + +1472 +01:10:57,430 --> 01:10:59,507 +So we'll do that in a second. + +1473 +01:10:59,507 --> 01:11:02,913 +And the label for this Button +is going to be an Image. + +1474 +01:11:04,090 --> 01:11:05,007 +I'll use the systemName here. + +1475 +01:11:05,007 --> 01:11:08,980 +I'm gonna do plus, again, I +got that by going over here + +1476 +01:11:08,980 --> 01:11:10,960 +to SF Symbols and searching around + +1477 +01:11:10,960 --> 01:11:12,980 +for what made sense for plus. + +1478 +01:11:12,980 --> 01:11:14,900 +I'll also do large scale here. + +1479 +01:11:14,900 --> 01:11:16,733 +Make this Button big. + +1480 +01:11:17,844 --> 01:11:20,520 +And what I'm gonna do when +this plus Button is clicked? + +1481 +01:11:20,520 --> 01:11:23,067 +No problem store, addDocument, + +1482 +01:11:23,067 --> 01:11:25,593 +just add a document to our store. + +1483 +01:11:26,777 --> 01:11:29,450 +So we're adding this +Button to the bar items + +1484 +01:11:29,450 --> 01:11:34,000 +on the leading edge of +this NavigationView. + +1485 +01:11:34,000 --> 01:11:34,860 +There it is right there. + +1486 +01:11:34,860 --> 01:11:37,300 +Notice that our plus +Button is not there here. + +1487 +01:11:37,300 --> 01:11:40,260 +Instead, we have this going +back Button right there. + +1488 +01:11:40,260 --> 01:11:41,530 +It's 'cause when we're over here, + +1489 +01:11:41,530 --> 01:11:43,800 +this navigationBarItems was not added + +1490 +01:11:43,800 --> 01:11:45,577 +up here to the EmojiArtDocumentView + +1491 +01:11:45,577 --> 01:11:49,250 +and we're showing this +EmojiArtDocumentView + +1492 +01:11:49,250 --> 01:11:51,050 +over here when we click on it, + +1493 +01:11:51,050 --> 01:11:53,000 +and so it doesn't get that plus Button. + +1494 +01:11:53,930 --> 01:11:55,560 +Let's try plus. + +1495 +01:11:55,560 --> 01:11:59,890 +Woo, got another untitled +document right here, nice! + +1496 +01:11:59,890 --> 01:12:03,840 +Now we could also add +some bar items over here + +1497 +01:12:03,840 --> 01:12:05,850 +in our EmojiArtDocumentView. + +1498 +01:12:05,850 --> 01:12:06,993 +For example, maybe it's time to make it + +1499 +01:12:06,993 --> 01:12:10,450 +so that this app is actually +usable on an iPhone, + +1500 +01:12:10,450 --> 01:12:13,350 +so we can set a background image. + +1501 +01:12:13,350 --> 01:12:16,560 +There's no drag-and-drop in iPhone, + +1502 +01:12:16,560 --> 01:12:18,940 +so to set a background image +we have to do a different way. + +1503 +01:12:18,940 --> 01:12:22,660 +And just to be simple, +how about copy and paste? + +1504 +01:12:22,660 --> 01:12:24,327 +You go find the image +you want, you copy it, + +1505 +01:12:24,327 --> 01:12:26,400 +you come back here and hit paste. + +1506 +01:12:26,400 --> 01:12:27,780 +And I'm gonna have the paste here, + +1507 +01:12:27,780 --> 01:12:30,400 +be a little button in the upper right. + +1508 +01:12:30,400 --> 01:12:32,170 +Now since I only want this Paste button + +1509 +01:12:32,170 --> 01:12:34,630 +to appear when I'm showing a document, + +1510 +01:12:34,630 --> 01:12:37,780 +I'm gonna put the code for this Button + +1511 +01:12:37,780 --> 01:12:41,980 +in EmojiArtDocumentView, 'cause +that's what's showing here, + +1512 +01:12:41,980 --> 01:12:43,897 +so that's what's gonna +control this Button. + +1513 +01:12:43,897 --> 01:12:46,200 +So I'm gonna go to EmojiArtDocumentView. + +1514 +01:12:46,200 --> 01:12:48,870 +And let's go down, maybe +right here after onDrop + +1515 +01:12:50,330 --> 01:12:53,563 +and add navigationBarItems here. + +1516 +01:12:54,900 --> 01:12:58,383 +This time I want it to be +on the trailing side of it. + +1517 +01:12:59,320 --> 01:13:02,133 +And let's just make another Button. + +1518 +01:13:03,112 --> 01:13:08,112 +And this Button with +the action in the second + +1519 +01:13:08,410 --> 01:13:13,410 +and the label, let's have the +label be an image system name. + +1520 +01:13:15,780 --> 01:13:18,840 +And I searched around SF +Symbols I found one kinda cool, + +1521 +01:13:18,840 --> 01:13:22,450 +doc on clipboard, + +1522 +01:13:22,450 --> 01:13:24,940 +so this is an icon that shows + +1523 +01:13:24,940 --> 01:13:27,490 +when there's a doc on the clipboard. + +1524 +01:13:27,490 --> 01:13:29,853 +Let's go imageScale large again. + +1525 +01:13:31,000 --> 01:13:34,430 +And so that's really cool, +perfect image for doing that. + +1526 +01:13:34,430 --> 01:13:36,930 +And what are we gonna do +when they try to paste + +1527 +01:13:36,930 --> 01:13:37,930 +from the pasteboard? + +1528 +01:13:37,930 --> 01:13:39,210 +Well, we're gonna paste +from the Pasteboard, + +1529 +01:13:39,210 --> 01:13:41,830 +which turns out to be +really easy to do in iOS. + +1530 +01:13:41,830 --> 01:13:46,830 +I'm gonna say if let URL equal +my general Pasteboard URL var + +1531 +01:13:49,300 --> 01:13:51,230 +if that's not nil, + +1532 +01:13:51,230 --> 01:13:55,050 +then I'm gonna set my +document's backgroundURL + +1533 +01:13:55,050 --> 01:13:55,950 +equal to that URL. + +1534 +01:13:56,930 --> 01:13:59,270 +So let's understand the +Pasteboard a little bit here. + +1535 +01:13:59,270 --> 01:14:01,670 +Pasteboard.general is a shared Pasteboard + +1536 +01:14:01,670 --> 01:14:05,060 +that represents the +Pasteboard on this device. + +1537 +01:14:05,060 --> 01:14:09,530 +It has a lot of different +vars, like string, url, + +1538 +01:14:09,530 --> 01:14:12,500 +other kinds of types, where +if the thing on the Pasteboard + +1539 +01:14:12,500 --> 01:14:16,210 +can be representative of +that, it returns non nil here. + +1540 +01:14:16,210 --> 01:14:18,620 +So if there's a URL in the Pasteboard, + +1541 +01:14:18,620 --> 01:14:21,570 +we're going to try and set it +as our background right here. + +1542 +01:14:22,690 --> 01:14:23,890 +Let's see if that works. + +1543 +01:14:26,789 --> 01:14:27,877 +So I have hello world here. + +1544 +01:14:27,877 --> 01:14:28,880 +Oh, there it is. + +1545 +01:14:28,880 --> 01:14:30,820 +Click, that's not doing anything. + +1546 +01:14:30,820 --> 01:14:33,791 +Let's go see if we can put +something in the Pasteboard. + +1547 +01:14:33,791 --> 01:14:36,363 +Let's go get my favorite image over there. + +1548 +01:14:37,650 --> 01:14:39,760 +Which is not this one. + +1549 +01:14:39,760 --> 01:14:41,990 +I like this one right here. + +1550 +01:14:41,990 --> 01:14:42,823 +There it is. + +1551 +01:14:42,823 --> 01:14:45,840 +I'm just gonna press +and hold and say copy. + +1552 +01:14:45,840 --> 01:14:48,510 +So let's say copy an image in iOS. + +1553 +01:14:48,510 --> 01:14:50,870 +Go back here and paste. + +1554 +01:14:50,870 --> 01:14:52,997 +Woo, it worked. + +1555 +01:14:52,997 --> 01:14:56,120 +Look at that, I can zoom in, nice! + +1556 +01:14:56,120 --> 01:14:58,010 +I can even play a little soccer + +1557 +01:14:58,010 --> 01:14:59,800 +in the front yard right here. + +1558 +01:14:59,800 --> 01:15:01,370 +Okay, excellent. + +1559 +01:15:01,370 --> 01:15:04,230 +So this is fantastic. + +1560 +01:15:04,230 --> 01:15:06,090 +Unfortunately, when I did this one, + +1561 +01:15:06,090 --> 01:15:08,440 +I found another little +bug in our Emoji Art. + +1562 +01:15:08,440 --> 01:15:09,347 +Watch this. + +1563 +01:15:09,347 --> 01:15:11,160 +I'm gonna go back out, and let's go back. + +1564 +01:15:11,160 --> 01:15:15,710 +Oh no, there's my emoji, but +I lost my background image. + +1565 +01:15:15,710 --> 01:15:18,870 +And that turns out in our +EmojiArt background View, + +1566 +01:15:18,870 --> 01:15:21,960 +we did a pretty good job +when we zoomed to fit + +1567 +01:15:21,960 --> 01:15:25,170 +of protecting against the +image being zero size, + +1568 +01:15:25,170 --> 01:15:29,190 +but we forgot to protect against +the View being zero size. + +1569 +01:15:29,190 --> 01:15:31,750 +Because when that View +is coming on screen, + +1570 +01:15:31,750 --> 01:15:34,920 +it seems to be momentarily +have zero height. + +1571 +01:15:34,920 --> 01:15:37,970 +I'm not sure exactly what +process is happening. + +1572 +01:15:37,970 --> 01:15:40,670 +But we zoom to fit it +to zero at that point. + +1573 +01:15:40,670 --> 01:15:43,110 +So I'm also going to +check here and zoom to fit + +1574 +01:15:43,110 --> 01:15:45,690 +that my size.height is greater than zero, + +1575 +01:15:45,690 --> 01:15:47,810 +and my size.width is greater than zero. + +1576 +01:15:47,810 --> 01:15:50,230 +I'm just being more +protective in zoom to fit, + +1577 +01:15:50,230 --> 01:15:54,340 +so that it doesn't set the +zoomScale here to zero. + +1578 +01:15:54,340 --> 01:15:55,890 +I never want my zoomScale to be zero + +1579 +01:15:55,890 --> 01:15:58,240 +'cause then I can't see my document. + +1580 +01:15:58,240 --> 01:16:01,410 +If I go back here to my simulator, + +1581 +01:16:01,410 --> 01:16:02,720 +I can actually double tap + +1582 +01:16:02,720 --> 01:16:05,700 +and it will zoom it up +from zero, which is good, + +1583 +01:16:05,700 --> 01:16:08,150 +but I don't ever want to +put it in that zero stage. + +1584 +01:16:08,150 --> 01:16:11,023 +So let's do this fix right here. + +1585 +01:16:12,000 --> 01:16:15,250 +So hello world, here's +our document right here. + +1586 +01:16:15,250 --> 01:16:16,900 +Maybe we'll zoom it way out, + +1587 +01:16:16,900 --> 01:16:19,550 +and we'll go out in the back end. + +1588 +01:16:19,550 --> 01:16:21,240 +Okay, well now interesting. + +1589 +01:16:21,240 --> 01:16:24,550 +So it did not zoom to zero. + +1590 +01:16:24,550 --> 01:16:27,750 +But it zoomed to back up to its full size, + +1591 +01:16:27,750 --> 01:16:29,950 +even though I had zoomed it down, + +1592 +01:16:29,950 --> 01:16:33,550 +when I went out and back, +it lost that zooming. + +1593 +01:16:33,550 --> 01:16:36,690 +And this is something to consider +when you have these Views + +1594 +01:16:36,690 --> 01:16:38,860 +coming and going because of navigation. + +1595 +01:16:38,860 --> 01:16:41,053 +So I'm navigating out and back in. + +1596 +01:16:41,930 --> 01:16:44,780 +When you're doing this, these +Views are being reconstructed, + +1597 +01:16:44,780 --> 01:16:47,920 +and their @State is mostly preserved, + +1598 +01:16:47,920 --> 01:16:52,020 +but some kind of State +may not be preserved. + +1599 +01:16:52,020 --> 01:16:55,570 +And for example, our scaling State + +1600 +01:16:55,570 --> 01:16:58,670 +is not preserved across doing this. + +1601 +01:16:58,670 --> 01:17:01,050 +Now, if you want State +to be preserved, though, + +1602 +01:17:01,050 --> 01:17:02,700 +there's a great place to do it. + +1603 +01:17:02,700 --> 01:17:04,240 +Your ViewModel. + +1604 +01:17:04,240 --> 01:17:06,970 +Okay, no matter how what is +happening on the View side, + +1605 +01:17:06,970 --> 01:17:09,320 +if your ViewModel is holding on to it, + +1606 +01:17:09,320 --> 01:17:10,360 +it's going to be preserved. + +1607 +01:17:10,360 --> 01:17:12,940 +Now, that's not the same +as putting it in the Model. + +1608 +01:17:12,940 --> 01:17:15,710 +I don't want the scaling +to be part of the Model, + +1609 +01:17:15,710 --> 01:17:20,610 +the Model is the house and +whatever emojis there are, + +1610 +01:17:20,610 --> 01:17:22,930 +but it doesn't include how scaled it is. + +1611 +01:17:22,930 --> 01:17:24,700 +But putting it in my ViewModel, + +1612 +01:17:24,700 --> 01:17:26,140 +if my ViewModel doesn't turn around + +1613 +01:17:26,140 --> 01:17:29,060 +and put it in the Model, +is perfectly fine to do + +1614 +01:17:29,060 --> 01:17:31,660 +and it provides sharing +across multiple Views + +1615 +01:17:31,660 --> 01:17:36,070 +that might be looking at +this same document ViewModel. + +1616 +01:17:36,070 --> 01:17:37,280 +So let's go do that. + +1617 +01:17:37,280 --> 01:17:38,230 +How would we do that? + +1618 +01:17:38,230 --> 01:17:41,560 +I'm just gonna make it here +so that our steady state, + +1619 +01:17:41,560 --> 01:17:45,141 +let's search where's our +steadyStatePanOffset, here it is. + +1620 +01:17:45,141 --> 01:17:47,001 +So here's steadyStatePanOffset, + +1621 +01:17:47,001 --> 01:17:50,877 +and here's our +steadyStateZoomOffset up here. + +1622 +01:17:50,877 --> 01:17:52,396 +And we're gonna have +these instead of being + +1623 +01:17:52,396 --> 01:17:54,750 +@State in our View, + +1624 +01:17:54,750 --> 01:17:56,943 +we're gonna put them into our ViewModel. + +1625 +01:17:57,830 --> 01:18:00,393 +So let's do that, let's +cut these outta here. + +1626 +01:18:03,272 --> 01:18:05,570 +And put them in our ViewModel +which is right here. + +1627 +01:18:05,570 --> 01:18:08,693 +And we'll put it, again and I think. + +1628 +01:18:09,560 --> 01:18:11,800 +And of course, they're not +State in the ViewModel, + +1629 +01:18:11,800 --> 01:18:13,893 +instead, they'd be @Published. + +1630 +01:18:15,500 --> 01:18:16,670 +And I'm not gonna make them private, + +1631 +01:18:16,670 --> 01:18:20,807 +'cause I'm gonna allow my +View to set them and get them. + +1632 +01:18:20,807 --> 01:18:23,400 +In my View over here, I'm +just gonna replace everywhere + +1633 +01:18:23,400 --> 01:18:28,400 +I have steady State with +document.steadyState instead. + +1634 +01:18:32,458 --> 01:18:34,093 +So just to do that everywhere. + +1635 +01:18:35,730 --> 01:18:38,670 +We go back to our panOffset, here we go. + +1636 +01:18:38,670 --> 01:18:39,670 +Now, let's try that. + +1637 +01:18:43,618 --> 01:18:45,530 +All right, Hello World, here it is. + +1638 +01:18:45,530 --> 01:18:47,000 +Now, let's zoom out. + +1639 +01:18:47,000 --> 01:18:50,690 +This zooming is being +kept in our ViewModel. + +1640 +01:18:50,690 --> 01:18:53,180 +So now if we go back and come back in, + +1641 +01:18:53,180 --> 01:18:54,660 +it's still there in our ViewModel, + +1642 +01:18:54,660 --> 01:18:56,833 +even though this View has gotten rebuilt. + +1643 +01:18:58,180 --> 01:19:00,080 +Now, there's a little +more that we could do here + +1644 +01:19:00,080 --> 01:19:01,820 +to be nicer to our user. + +1645 +01:19:01,820 --> 01:19:06,080 +One thing is this little button, +a lot of times you click it + +1646 +01:19:06,080 --> 01:19:07,540 +and nothing happens, okay. + +1647 +01:19:07,540 --> 01:19:11,110 +We go over here and we click +it, nothing's happening, okay? + +1648 +01:19:11,110 --> 01:19:12,530 +That thing is no longer in the pasteboard, + +1649 +01:19:12,530 --> 01:19:15,460 +I copied and pasted this steady +state thing, so it's gone. + +1650 +01:19:15,460 --> 01:19:17,980 +So I'm not getting my user much feedback + +1651 +01:19:17,980 --> 01:19:19,730 +about what this button does. + +1652 +01:19:19,730 --> 01:19:20,660 +It's not clear. + +1653 +01:19:20,660 --> 01:19:24,010 +I guess it looks like something +copied on the Pasteboard, + +1654 +01:19:24,010 --> 01:19:27,960 +I guess, but it's like, +what are we going to do + +1655 +01:19:27,960 --> 01:19:30,670 +to make this give some feedback. + +1656 +01:19:30,670 --> 01:19:33,410 +So how about if they click on this + +1657 +01:19:33,410 --> 01:19:35,900 +and it's not going to do something there, + +1658 +01:19:35,900 --> 01:19:40,090 +we put up a little Alert +that explains what this is. + +1659 +01:19:40,090 --> 01:19:41,220 +So that gives us an opportunity + +1660 +01:19:41,220 --> 01:19:43,640 +to learn how to put Alerts up. + +1661 +01:19:43,640 --> 01:19:45,863 +And putting Alerts up, quite easy. + +1662 +01:19:45,863 --> 01:19:48,610 +You can go over here and +put it on this Image. + +1663 +01:19:48,610 --> 01:19:52,420 +If you click on this Image, +we want to put an Alert up. + +1664 +01:19:52,420 --> 01:19:57,420 +Now, Alerts are interesting +little ViewModifiers here. + +1665 +01:19:58,750 --> 01:20:01,275 +They start out looking +a lot like a popover. + +1666 +01:20:01,275 --> 01:20:02,610 +You can see that they've got the + +1667 +01:20:02,610 --> 01:20:04,530 +Identifiable Binding version + +1668 +01:20:04,530 --> 01:20:07,300 +if you wanna put different +things up in your Alert + +1669 +01:20:07,300 --> 01:20:08,347 +depending on what's going on. + +1670 +01:20:08,347 --> 01:20:10,760 +But it also has this nice isPresented, + +1671 +01:20:10,760 --> 01:20:12,380 +which is the one we're going to use. + +1672 +01:20:12,380 --> 01:20:16,830 +And we're gonna need to have +some sort of boolean var + +1673 +01:20:16,830 --> 01:20:18,550 +that says whether this Alert should be up, + +1674 +01:20:18,550 --> 01:20:21,480 +and I'm gonna call it +explainBackgroundPaste. + +1675 +01:20:23,088 --> 01:20:28,009 +This is gonna be my State private var, + +1676 +01:20:28,009 --> 01:20:30,529 +explainBackgroundPaste. + +1677 +01:20:30,529 --> 01:20:31,620 +I'm gonna start it out as false. + +1678 +01:20:31,620 --> 01:20:34,180 +I don't want that Alert +showing when we first come up. + +1679 +01:20:34,180 --> 01:20:37,960 +And I just need to set this to +make this Alert be presented. + +1680 +01:20:37,960 --> 01:20:39,520 +And where am I gonna set that? + +1681 +01:20:39,520 --> 01:20:40,670 +I'm gonna set it here. + +1682 +01:20:40,670 --> 01:20:44,630 +I'm gonna set it anytime that I'm not + +1683 +01:20:44,630 --> 01:20:45,868 +updating the background here. + +1684 +01:20:45,868 --> 01:20:48,560 +So I'm gonna say else if I'm +not updating the background, + +1685 +01:20:48,560 --> 01:20:51,130 +if it would just be clicking +the Button and doing nothing. + +1686 +01:20:51,130 --> 01:20:55,833 +And I'm gonna say +self.explainBackgroundPaste equals true. + +1687 +01:20:56,790 --> 01:20:59,383 +That's gonna cause this Alert to show up. + +1688 +01:20:59,383 --> 01:21:03,320 +I think we'll also do this if the URL + +1689 +01:21:03,320 --> 01:21:07,813 +does not equal to our +existing backgroundURL, + +1690 +01:21:09,310 --> 01:21:12,540 +So if you've already pasted +and then you'd try paste again, + +1691 +01:21:12,540 --> 01:21:15,650 +then we won't paste, +instead, we'll explain + +1692 +01:21:15,650 --> 01:21:18,730 +this background paste +to you and how it works. + +1693 +01:21:18,730 --> 01:21:22,200 +Now, Alert doesn't have you present + +1694 +01:21:22,200 --> 01:21:24,340 +with a ViewBuilder here, + +1695 +01:21:24,340 --> 01:21:27,220 +you can see that its return +value of this little closure + +1696 +01:21:27,220 --> 01:21:30,270 +that you're giving an alert is +not a ViewBuilder or a View, + +1697 +01:21:30,270 --> 01:21:31,850 +it's an Alert. + +1698 +01:21:31,850 --> 01:21:35,370 +So we're actually going to +be returning an Alert here, + +1699 +01:21:35,370 --> 01:21:36,763 +return Alert. + +1700 +01:21:37,890 --> 01:21:40,630 +So Alert can provide messages +and then it can either have + +1701 +01:21:40,630 --> 01:21:43,150 +a single dismiss button, +like "Okay" button, + +1702 +01:21:43,150 --> 01:21:43,983 +that's what we want. + +1703 +01:21:43,983 --> 01:21:45,820 +Or it can actually have two buttons + +1704 +01:21:45,820 --> 01:21:48,640 +like an "Okay" button +and a "Cancel" button. + +1705 +01:21:48,640 --> 01:21:52,620 +So let's go ahead and use this +one that just has a single. + +1706 +01:21:52,620 --> 01:21:55,720 +To make it clear here, I will +separate these arguments out + +1707 +01:21:55,720 --> 01:21:57,543 +so you can see them better. + +1708 +01:21:58,770 --> 01:22:00,003 +Here's our Alert. + +1709 +01:22:01,040 --> 01:22:04,250 +And the title and the +message are both Text. + +1710 +01:22:04,250 --> 01:22:07,960 +So the title I'm gonna have +it be "Paste Background" + +1711 +01:22:07,960 --> 01:22:10,790 +'cause that's what the user tried to do. + +1712 +01:22:10,790 --> 01:22:12,820 +And then the message, + +1713 +01:22:12,820 --> 01:22:14,960 +let's say this is where we're +gonna explain ourselves, + +1714 +01:22:14,960 --> 01:22:19,960 +with a "Copy the URL of +an image to the clipboard + +1715 +01:22:21,640 --> 01:22:25,200 +and touch this button", the +one you just clicked on, + +1716 +01:22:25,200 --> 01:22:29,650 +"to make it the background +of your document." + +1717 +01:22:29,650 --> 01:22:32,450 +And this is the kind of thing +that first of all needs to be + +1718 +01:22:32,450 --> 01:22:34,520 +internationalizable to other languages. + +1719 +01:22:34,520 --> 01:22:36,870 +And also, we're gonna focus test + +1720 +01:22:36,870 --> 01:22:38,980 +and we're gonna have maybe documentation, + +1721 +01:22:38,980 --> 01:22:40,760 +people can help us pick good wording + +1722 +01:22:40,760 --> 01:22:43,130 +so that people won't be +confused by what's going on, + +1723 +01:22:43,130 --> 01:22:44,063 +et cetera, here. + +1724 +01:22:45,553 --> 01:22:47,240 +And then finally, we +have the "Dismiss" button + +1725 +01:22:47,240 --> 01:22:49,310 +which is of type Alert.Button. + +1726 +01:22:49,310 --> 01:22:51,260 +Now Alert.Button is a class that has + +1727 +01:22:51,260 --> 01:22:53,340 +a lot of static funcs on it, + +1728 +01:22:53,340 --> 01:22:55,857 +and some of them are default Buttons. + +1729 +01:22:55,857 --> 01:22:57,690 +That's just a normal Button. + +1730 +01:22:57,690 --> 01:23:00,030 +There's also destructive Buttons, + +1731 +01:23:00,030 --> 01:23:02,300 +and there are cancel Buttons. + +1732 +01:23:02,300 --> 01:23:05,140 +So in this case, we just +want the default Button + +1733 +01:23:05,140 --> 01:23:06,750 +and the label for it, + +1734 +01:23:06,750 --> 01:23:09,880 +it's just gonna be a Text that says, "OK." + +1735 +01:23:09,880 --> 01:23:14,510 +And this also takes a +closure that'll be executed + +1736 +01:23:14,510 --> 01:23:16,430 +when this Button is pressed. + +1737 +01:23:16,430 --> 01:23:18,910 +Now in our case, we +don't need to do anything + +1738 +01:23:18,910 --> 01:23:21,500 +when this OK is pressed, +we just want it to dismiss. + +1739 +01:23:21,500 --> 01:23:24,080 +And this default Button, +this "Dismiss" Button + +1740 +01:23:24,080 --> 01:23:26,833 +will set this back to false for us. + +1741 +01:23:28,370 --> 01:23:30,773 +This dollar by the way, always goes here. + +1742 +01:23:32,020 --> 01:23:35,460 +So we don't have to go in here +and set this back to false + +1743 +01:23:35,460 --> 01:23:38,173 +to cause our alert to go +away, it'll do that for us. + +1744 +01:23:39,795 --> 01:23:43,160 +Let's see how this +shows up in the UI here? + +1745 +01:23:43,160 --> 01:23:45,980 +Go back to Hello World, +here's our document. + +1746 +01:23:45,980 --> 01:23:48,220 +Click here, and it says, +oh, "Paste Background..." + +1747 +01:23:48,220 --> 01:23:51,170 +Copy this explains to me, +oh, what you're gonna do. + +1748 +01:23:51,170 --> 01:23:53,280 +Oh, okay, so I'll go do that. + +1749 +01:23:53,280 --> 01:23:54,600 +I'll go over here. + +1750 +01:23:54,600 --> 01:23:57,023 +This time, maybe I'll go and get the image + +1751 +01:23:57,023 --> 01:23:59,873 +I don't like quite as much, this guy. + +1752 +01:24:01,130 --> 01:24:03,193 +Right here, let's copy this. + +1753 +01:24:04,470 --> 01:24:05,570 +Go back here. + +1754 +01:24:05,570 --> 01:24:08,000 +Now hit paste, oh, pasted it. + +1755 +01:24:08,000 --> 01:24:10,223 +But actually, this is a +little scary that it pasted. + +1756 +01:24:10,223 --> 01:24:14,010 +This is kind of low res +version of our horses here. + +1757 +01:24:14,010 --> 01:24:15,380 +'Cause it's like, oh, ooh, + +1758 +01:24:15,380 --> 01:24:16,780 +I didn't know it was gonna do that. + +1759 +01:24:16,780 --> 01:24:18,310 +Wow, what the heck? + +1760 +01:24:18,310 --> 01:24:22,370 +So maybe we need a little bit +more alerting going on here, + +1761 +01:24:22,370 --> 01:24:25,720 +where if you click this and +it's going to do this background + +1762 +01:24:25,720 --> 01:24:28,030 +then it's going to ask you first + +1763 +01:24:28,030 --> 01:24:29,800 +if that's really what you want. + +1764 +01:24:29,800 --> 01:24:32,810 +So how do we put up an +Alert that asks us yes or no + +1765 +01:24:32,810 --> 01:24:34,610 +do we wanna do something? + +1766 +01:24:34,610 --> 01:24:36,530 +Well, same exact way where we're gonna + +1767 +01:24:36,530 --> 01:24:38,930 +have to have some State. + +1768 +01:24:38,930 --> 01:24:41,360 +So I'm gonna call this State + +1769 +01:24:41,360 --> 01:24:44,290 +instead of calling it +explainBackgroundPaste, + +1770 +01:24:44,290 --> 01:24:47,080 +I'm gonna call it confirmBackgroundPaste. + +1771 +01:24:49,065 --> 01:24:52,180 +And I'll just set this +confirmBackgroundPaste + +1772 +01:24:52,180 --> 01:24:54,155 +right here to true. + +1773 +01:24:54,155 --> 01:24:57,340 +ConfirmBackgroundPaste equals true. + +1774 +01:24:57,340 --> 01:25:00,153 +And now I need another Alert right here, + +1775 +01:25:00,153 --> 01:25:02,890 +another Alert that is going to + +1776 +01:25:02,890 --> 01:25:05,460 +react to this thing set to true. + +1777 +01:25:05,460 --> 01:25:08,070 +Now, something very important +to understand about Alerts. + +1778 +01:25:08,070 --> 01:25:13,070 +You cannot put two Alerts with +isPresented on the same View. + +1779 +01:25:13,600 --> 01:25:17,850 +So I cannot put another +Alert on Image right here, + +1780 +01:25:17,850 --> 01:25:19,720 +it has to be on some other View, + +1781 +01:25:19,720 --> 01:25:21,760 +or I have to use the other Alert + +1782 +01:25:21,760 --> 01:25:23,500 +which takes an Identifiable. + +1783 +01:25:23,500 --> 01:25:26,370 +And that Identifiable, usually an enum + +1784 +01:25:26,370 --> 01:25:29,737 +is going to pick which Alert +to show, this one or this one. + +1785 +01:25:29,737 --> 01:25:32,110 +And I might well decide that + +1786 +01:25:32,110 --> 01:25:33,570 +instead of having this be a Bool, + +1787 +01:25:33,570 --> 01:25:37,440 +I want this to be an enum +that has explain or confirm. + +1788 +01:25:37,440 --> 01:25:40,990 +And then I will do my +Alert with the finding + +1789 +01:25:40,990 --> 01:25:43,603 +being a Binding to a State with that enum. + +1790 +01:25:43,603 --> 01:25:45,680 +That probably will be +a better way to do it + +1791 +01:25:45,680 --> 01:25:47,500 +than these two Bools. + +1792 +01:25:47,500 --> 01:25:50,350 +But for demo purposes, +we'll keep going here. + +1793 +01:25:50,350 --> 01:25:51,870 +So where am I gonna put this alert + +1794 +01:25:51,870 --> 01:25:52,817 +since I can't put it on image? + +1795 +01:25:52,817 --> 01:25:54,970 +Oh, I can put it almost anywhere. + +1796 +01:25:54,970 --> 01:25:56,870 +This is our GeometryReader. + +1797 +01:25:56,870 --> 01:25:58,896 +This is our top level VStack. + +1798 +01:25:58,896 --> 01:26:00,680 +Go ahead and put it on +our top level VStack, + +1799 +01:26:00,680 --> 01:26:03,210 +but it really doesn't matter +as long as it's a View + +1800 +01:26:03,210 --> 01:26:05,930 +that's on the screen at +the time this happens. + +1801 +01:26:05,930 --> 01:26:10,100 +And I'm going to type this +in really fast, there we go. + +1802 +01:26:10,100 --> 01:26:11,670 +And this one, it's similar, right? + +1803 +01:26:11,670 --> 01:26:12,640 +Alert is presented, + +1804 +01:26:12,640 --> 01:26:16,930 +it's using this confirm as the +decision maker, same title. + +1805 +01:26:16,930 --> 01:26:19,390 +Here it's saying, "Replace +your background with." + +1806 +01:26:19,390 --> 01:26:21,770 +And now it's showing you +the URL it's going to use + +1807 +01:26:21,770 --> 01:26:24,580 +that's kinda cool, it's in the pasteboard. + +1808 +01:26:24,580 --> 01:26:27,000 +And now I have a +primaryButton, which is again, + +1809 +01:26:27,000 --> 01:26:31,550 +a default Text, OK, but now +I am providing a closure. + +1810 +01:26:31,550 --> 01:26:33,420 +So now when this OK button is pressed, + +1811 +01:26:33,420 --> 01:26:36,850 +I am going to set my +background URL to general URL. + +1812 +01:26:36,850 --> 01:26:38,460 +That's the code that used to be up here, + +1813 +01:26:38,460 --> 01:26:39,890 +now I'm putting it down here. + +1814 +01:26:39,890 --> 01:26:44,427 +It only happens if I click +OK in this Alert, right? + +1815 +01:26:44,427 --> 01:26:48,100 +And now I have a second Button +which is a .cancel Button. + +1816 +01:26:48,100 --> 01:26:52,120 +Remember, these are all +Alert.Button.cancel. + +1817 +01:26:52,120 --> 01:26:54,300 +And Swift is just inferring that + +1818 +01:26:54,300 --> 01:26:56,963 +because it knows this argument +takes an Alert.Button. + +1819 +01:26:57,835 --> 01:26:59,643 +Let's see this one in action. + +1820 +01:27:03,020 --> 01:27:06,270 +Go to "Hello World" document +right here and click. + +1821 +01:27:06,270 --> 01:27:07,730 +Oh, it's telling you copy the URL. + +1822 +01:27:07,730 --> 01:27:09,610 +Okay, I'm gonna go do that. + +1823 +01:27:09,610 --> 01:27:11,150 +Go back here. + +1824 +01:27:11,150 --> 01:27:16,150 +Let's go back, go back +to our favorite one. + +1825 +01:27:16,530 --> 01:27:19,750 +Copy it over here. + +1826 +01:27:19,750 --> 01:27:23,410 +And now when I hit this, it +should come ask me to confirm. + +1827 +01:27:23,410 --> 01:27:26,445 +Oh, "Replace your +background with this URL?" + +1828 +01:27:26,445 --> 01:27:29,100 +And I can either say, +"Cancel, no, don't do it." + +1829 +01:27:29,100 --> 01:27:31,200 +Or I can over here and say, "Yeah, do it." + +1830 +01:27:32,070 --> 01:27:32,903 +So that's alert. + +1831 +01:27:32,903 --> 01:27:34,580 +So we've learned Alert, +we've learned sheet, + +1832 +01:27:34,580 --> 01:27:36,490 +we've learned popovers, +we've learned NavigationView. + +1833 +01:27:36,490 --> 01:27:38,930 +And there's a lot of different ways + +1834 +01:27:38,930 --> 01:27:43,170 +to decide how to build your UI here + +1835 +01:27:43,170 --> 01:27:46,713 +to get the information in front +of the user as best you can. + +1836 +01:27:48,160 --> 01:27:50,510 +Now, one last thing I wanna do + +1837 +01:27:50,510 --> 01:27:55,370 +is to have this View right here +be a little more changeable. + +1838 +01:27:55,370 --> 01:27:56,850 +For example, I'd like to be able to + +1839 +01:27:56,850 --> 01:27:58,680 +delete items that I want. + +1840 +01:27:58,680 --> 01:28:00,260 +I'd like to like swiping to delete + +1841 +01:28:00,260 --> 01:28:02,380 +or somehow clicking to delete. + +1842 +01:28:02,380 --> 01:28:04,760 +And I wanna be able to +rename my documents. + +1843 +01:28:04,760 --> 01:28:06,880 +Okay, there's no way to, these Untitled's + +1844 +01:28:06,880 --> 01:28:08,270 +I can't give them names, + +1845 +01:28:08,270 --> 01:28:10,750 +so how am I gonna rename these documents? + +1846 +01:28:10,750 --> 01:28:11,996 +So let's get it out. + +1847 +01:28:11,996 --> 01:28:15,240 +It turns out to be really +easy to make delete work. + +1848 +01:28:15,240 --> 01:28:17,020 +All you have to do to make delete work, + +1849 +01:28:17,020 --> 01:28:19,220 +it's a function in ForEach. + +1850 +01:28:19,220 --> 01:28:22,273 +So if you are in your +ForEach say onDelete, + +1851 +01:28:23,150 --> 01:28:25,463 +it will give you what's +called an indexSet. + +1852 +01:28:27,052 --> 01:28:31,450 +So an indexSet is kind of +like an Array of indices, + +1853 +01:28:31,450 --> 01:28:33,980 +and it's telling you the +things that were deleted. + +1854 +01:28:33,980 --> 01:28:36,210 +Now in iOS, you're doing swipe to delete, + +1855 +01:28:36,210 --> 01:28:39,550 +this is always going to be an +Array with one thing in it. + +1856 +01:28:39,550 --> 01:28:41,650 +But we're still going to +try and write our code + +1857 +01:28:41,650 --> 01:28:44,800 +in general terms so that we +can go through all of these + +1858 +01:28:44,800 --> 01:28:47,240 +things in there and delete them all. + +1859 +01:28:47,240 --> 01:28:50,350 +I'm gonna write the code that +does the delete of this store + +1860 +01:28:50,350 --> 01:28:54,480 +in a little bit of what you +might call advanced Swift, + +1861 +01:28:54,480 --> 01:28:57,100 +but I'm just using the +primitives in Swift, + +1862 +01:28:57,100 --> 01:29:00,830 +specifically in indexSet and +in Array to write this code + +1863 +01:29:00,830 --> 01:29:02,530 +a little more succinctly. + +1864 +01:29:02,530 --> 01:29:03,497 +So watch me do this. + +1865 +01:29:03,497 --> 01:29:07,890 +I'm gonna take the indexSet +and I'm gonna map it + +1866 +01:29:07,890 --> 01:29:12,890 +to getting from my store the +documents at those indices. + +1867 +01:29:13,540 --> 01:29:18,540 +So now I have an Array of +documents at those indexes. + +1868 +01:29:18,940 --> 01:29:22,070 +And I'm gonna ask that +Array for each of them, + +1869 +01:29:22,070 --> 01:29:23,923 +each of the documents that is, + +1870 +01:29:25,360 --> 01:29:30,153 +just ask the store to +remove that document. + +1871 +01:29:32,330 --> 01:29:34,740 +This is succinct way of basically saying, + +1872 +01:29:34,740 --> 01:29:36,470 +for all the things in the indexSet + +1873 +01:29:36,470 --> 01:29:38,221 +just remove that document. + +1874 +01:29:38,221 --> 01:29:39,810 +And we're doing it by having a little map + +1875 +01:29:39,810 --> 01:29:43,743 +in between the maps the +indexes to the documents. + +1876 +01:29:45,100 --> 01:29:46,920 +So this kind of coding right here, + +1877 +01:29:46,920 --> 01:29:49,400 +eventually, you'll get used to doing this. + +1878 +01:29:49,400 --> 01:29:52,290 +Real Swift programmers +are doing stuff like this. + +1879 +01:29:52,290 --> 01:29:54,720 +This is actually just as +easy if not easier to read + +1880 +01:29:54,720 --> 01:29:57,300 +than having two for loops +here that are going through + +1881 +01:29:57,300 --> 01:29:59,600 +the indexSet and then going +through the documents. + +1882 +01:29:59,600 --> 01:30:01,360 +That's like six or seven lines of code, + +1883 +01:30:01,360 --> 01:30:03,070 +a lot to read and parse, + +1884 +01:30:03,070 --> 01:30:07,930 +whereas this is much more +straightforward to read. + +1885 +01:30:10,730 --> 01:30:12,373 +So let's see this in action. + +1886 +01:30:13,240 --> 01:30:15,470 +Anytime you have a delete +there and you're in the list, + +1887 +01:30:15,470 --> 01:30:17,770 +I can swipe to delete, you see that? + +1888 +01:30:17,770 --> 01:30:19,600 +I just swiped left. + +1889 +01:30:19,600 --> 01:30:20,710 +Now, if I don't want delete, + +1890 +01:30:20,710 --> 01:30:21,690 +I can push it back to the right. + +1891 +01:30:21,690 --> 01:30:24,640 +If I swipe to delete all +the way and it goes away. + +1892 +01:30:24,640 --> 01:30:26,940 +Or I can swipe to delete partially + +1893 +01:30:26,940 --> 01:30:29,390 +and confirm by pressing that button. + +1894 +01:30:29,390 --> 01:30:31,760 +So that's how the delete works. + +1895 +01:30:31,760 --> 01:30:34,763 +Now, you can still add +documents back here. + +1896 +01:30:36,000 --> 01:30:37,800 +That's one way to do delete, + +1897 +01:30:37,800 --> 01:30:39,610 +and it's a nice way to do it. + +1898 +01:30:39,610 --> 01:30:42,720 +There's another way, which +is there's a special button + +1899 +01:30:42,720 --> 01:30:44,643 +in iOS that you can put +called the edit button. + +1900 +01:30:44,643 --> 01:30:46,290 +And I'm gonna put it up here + +1901 +01:30:46,290 --> 01:30:49,990 +in the trailing situation in this View. + +1902 +01:30:49,990 --> 01:30:51,820 +And this will put you in an edit mode + +1903 +01:30:51,820 --> 01:30:55,060 +where there are little +delete buttons on each line. + +1904 +01:30:55,060 --> 01:30:56,320 +So how do we do that? + +1905 +01:30:56,320 --> 01:30:58,690 +Here's the leading +button for my bar items. + +1906 +01:30:58,690 --> 01:31:02,150 +I'm going to add the trailing button. + +1907 +01:31:02,150 --> 01:31:04,870 +And this is just gonna be the EditButton. + +1908 +01:31:04,870 --> 01:31:08,640 +Okay, so EditButton is a SwiftUI struct. + +1909 +01:31:08,640 --> 01:31:11,110 +And when you put the EditButton in here, + +1910 +01:31:11,110 --> 01:31:13,750 +and you click edit, if +you have a List here, + +1911 +01:31:13,750 --> 01:31:16,160 +and there's a onDelete on your ForEach, + +1912 +01:31:16,160 --> 01:31:18,190 +it will put you in this +mode where you can delete + +1913 +01:31:18,190 --> 01:31:20,963 +by clicking these instead +of doing swipe to delete. + +1914 +01:31:22,070 --> 01:31:23,440 +That's pretty cool, right? + +1915 +01:31:23,440 --> 01:31:26,780 +A little delete/edit mode right there. + +1916 +01:31:26,780 --> 01:31:28,180 +Now, the last thing I wanna do + +1917 +01:31:28,180 --> 01:31:30,900 +is be able to edit my document names, + +1918 +01:31:30,900 --> 01:31:32,880 +but I really wanna be able to edit them + +1919 +01:31:32,880 --> 01:31:35,040 +just by clicking on them to edit them. + +1920 +01:31:35,040 --> 01:31:37,600 +But I don't really wanna +click on them to edit them + +1921 +01:31:37,600 --> 01:31:40,420 +when it's like this because +I wanna show my document. + +1922 +01:31:40,420 --> 01:31:43,310 +But how about when it's in edit mode? + +1923 +01:31:43,310 --> 01:31:44,510 +See when it's in edit mode, + +1924 +01:31:44,510 --> 01:31:46,840 +and I clicked it doesn't navigate anyway, + +1925 +01:31:46,840 --> 01:31:48,480 +because I'm editing it. + +1926 +01:31:48,480 --> 01:31:51,080 +So this would be a great +time if I clicked on these + +1927 +01:31:51,080 --> 01:31:53,120 +to have them edit in place, + +1928 +01:31:53,120 --> 01:31:56,643 +just turn these Texts into TextFields. + +1929 +01:31:57,790 --> 01:31:59,870 +But we need to find out + +1930 +01:31:59,870 --> 01:32:03,430 +when this done button is clicked, right? + +1931 +01:32:03,430 --> 01:32:05,230 +And this done button clicking + +1932 +01:32:05,230 --> 01:32:08,566 +actually affects something +in your @Environment. + +1933 +01:32:08,566 --> 01:32:11,560 +Do you remember those +@Environments like colorScheme? + +1934 +01:32:11,560 --> 01:32:14,570 +Well, there's another one +there called editMode. + +1935 +01:32:14,570 --> 01:32:16,270 +And it's a kind of a special one. + +1936 +01:32:16,270 --> 01:32:18,610 +So we're gonna go take a look at that one + +1937 +01:32:18,610 --> 01:32:19,833 +in the documentation. + +1938 +01:32:20,920 --> 01:32:23,110 +Here's EnvironmentValues right here. + +1939 +01:32:23,110 --> 01:32:25,620 +And EnvironmentValues is +the thing that's listing + +1940 +01:32:25,620 --> 01:32:27,580 +all these stuff by color scheme, + +1941 +01:32:27,580 --> 01:32:29,370 +and all the things that +can be in your environment. + +1942 +01:32:29,370 --> 01:32:31,960 +And one of them is editMode right here, + +1943 +01:32:31,960 --> 01:32:33,356 +you see this editMode? + +1944 +01:32:33,356 --> 01:32:35,960 +But look at the type of +editMode, let's click on it, + +1945 +01:32:35,960 --> 01:32:39,178 +it is a Binding to an EditMode. + +1946 +01:32:39,178 --> 01:32:41,380 +And an EditMode is just an enum + +1947 +01:32:41,380 --> 01:32:43,930 +that has active, inactive or transient. + +1948 +01:32:43,930 --> 01:32:46,480 +It has a nice var, whether +we're editing or not. + +1949 +01:32:46,480 --> 01:32:47,440 +So this makes sense. + +1950 +01:32:47,440 --> 01:32:49,970 +I've got this EditMode, +whether I'm editing or not, + +1951 +01:32:49,970 --> 01:32:52,120 +but why is it a Binding, + +1952 +01:32:52,120 --> 01:32:55,200 +and not only a Binding +an Optional Binding? + +1953 +01:32:55,200 --> 01:32:57,890 +Notice also that this is get set. + +1954 +01:32:57,890 --> 01:33:01,150 +So this environment value +we can actually set. + +1955 +01:33:01,150 --> 01:33:03,880 +So if you wanna know +whether that done button is + +1956 +01:33:03,880 --> 01:33:08,090 +has been activated or +not, you're going to set + +1957 +01:33:08,090 --> 01:33:11,230 +this environment variable to be a Binding + +1958 +01:33:11,230 --> 01:33:14,920 +to some editMode State in your View. + +1959 +01:33:14,920 --> 01:33:15,930 +That's how you get this. + +1960 +01:33:15,930 --> 01:33:19,240 +Now, why do they do this +indirection to the Binding? + +1961 +01:33:19,240 --> 01:33:21,460 +Well, because whenever that +done button is clicked, + +1962 +01:33:21,460 --> 01:33:24,540 +you want to find out, +and Bindings remember, + +1963 +01:33:24,540 --> 01:33:27,400 +when they change when the +value they point to changes, + +1964 +01:33:27,400 --> 01:33:29,380 +they cause your View to redraw, + +1965 +01:33:29,380 --> 01:33:31,410 +which is exactly what you want. + +1966 +01:33:31,410 --> 01:33:34,133 +So this is how we're going +to find out the editMode. + +1967 +01:33:34,133 --> 01:33:38,210 +Not a lot of the +EnvironmentValues are like this, + +1968 +01:33:38,210 --> 01:33:40,460 +whether you have Bindings and all this, + +1969 +01:33:40,460 --> 01:33:43,180 +but for editMode it makes perfect sense. + +1970 +01:33:43,180 --> 01:33:45,540 +So we're gonna have to +set this environment. + +1971 +01:33:45,540 --> 01:33:47,420 +Now, we didn't learn in the slides + +1972 +01:33:47,420 --> 01:33:48,820 +how to set the environment, + +1973 +01:33:48,820 --> 01:33:50,700 +we know how to get the environment, right? + +1974 +01:33:50,700 --> 01:33:55,700 +We do something like +@Environment, the \.editMode. + +1975 +01:33:56,670 --> 01:34:00,170 +And you can get the editMode +that way, but it's not, + +1976 +01:34:00,170 --> 01:34:03,098 +we don't want to get it +here, we want to set it. + +1977 +01:34:03,098 --> 01:34:07,515 +So the way we set environment +is we use .environment. + +1978 +01:34:08,560 --> 01:34:11,775 +And .environment takes the path editMode, + +1979 +01:34:11,775 --> 01:34:14,284 +and then it takes what +you wanna set it to. + +1980 +01:34:14,284 --> 01:34:16,040 +And remember, this is a Binding. + +1981 +01:34:16,040 --> 01:34:20,120 +So I'm gonna have to set a +Binding to some editMode. + +1982 +01:34:20,120 --> 01:34:24,130 +And so this is going to have +to be some State in our View. + +1983 +01:34:24,130 --> 01:34:28,550 +So @State private var editMode, + +1984 +01:34:28,550 --> 01:34:30,173 +which is of type EditMode. + +1985 +01:34:31,317 --> 01:34:32,583 +And this is a Binding. + +1986 +01:34:34,142 --> 01:34:35,520 +And a couple of things here. + +1987 +01:34:35,520 --> 01:34:38,910 +Notice this is a var, it +needs an initial value. + +1988 +01:34:38,910 --> 01:34:42,580 +And start with, it's +either gonna be .inactive, + +1989 +01:34:42,580 --> 01:34:46,440 +or .active, or .transient, +those are the three ones. + +1990 +01:34:46,440 --> 01:34:49,160 +And obviously when we +first start up our View, + +1991 +01:34:49,160 --> 01:34:49,993 +it's inactive. + +1992 +01:34:49,993 --> 01:34:52,750 +So we'll set that to inactive. + +1993 +01:34:52,750 --> 01:34:55,210 +The other thing that's super +important to understand + +1994 +01:34:55,210 --> 01:34:59,470 +is that .environment sets +that var in EnvironmentValues + +1995 +01:34:59,470 --> 01:35:02,610 +only for the View you call it on. + +1996 +01:35:02,610 --> 01:35:05,520 +Right, this is setting the environment + +1997 +01:35:05,520 --> 01:35:07,870 +for whatever View you call it on. + +1998 +01:35:07,870 --> 01:35:11,140 +This is the View I'm +calling environment on. + +1999 +01:35:11,140 --> 01:35:14,500 +So it is setting the +environment for this View. + +2000 +01:35:14,500 --> 01:35:17,720 +Now, this View in here somewhere + +2001 +01:35:17,720 --> 01:35:20,450 +has to have the EditButton. + +2002 +01:35:20,450 --> 01:35:22,920 +Okay, if the View you +set the environment on + +2003 +01:35:22,920 --> 01:35:24,380 +does not have the EditButton, + +2004 +01:35:24,380 --> 01:35:26,460 +then when the EditButton clicks, + +2005 +01:35:26,460 --> 01:35:28,250 +it's not gonna be setting this Binding + +2006 +01:35:28,250 --> 01:35:30,790 +'cause the Binding won't have +been set into environment. + +2007 +01:35:30,790 --> 01:35:32,650 +So that means we can't put the environment + +2008 +01:35:32,650 --> 01:35:34,790 +up here for example, you might think, + +2009 +01:35:34,790 --> 01:35:36,500 +oh, let's put the environment up here. + +2010 +01:35:36,500 --> 01:35:37,540 +Well, this won't work + +2011 +01:35:37,540 --> 01:35:41,070 +because this only sets the +environment for this View. + +2012 +01:35:41,070 --> 01:35:44,200 +And the EditButton isn't in this View. + +2013 +01:35:44,200 --> 01:35:46,950 +So the EditButton would +never see this environment. + +2014 +01:35:46,950 --> 01:35:50,990 +So we need this environment +down here, including it, + +2015 +01:35:50,990 --> 01:35:54,950 +whatever you send it to has +to include the EditButton, + +2016 +01:35:54,950 --> 01:35:57,220 +in this case, this var items. + +2017 +01:35:57,220 --> 01:35:58,283 +So make sense there? + +2018 +01:35:58,283 --> 01:36:00,630 +A little subtlety some people miss. + +2019 +01:36:00,630 --> 01:36:02,340 +But when you set the environment, + +2020 +01:36:02,340 --> 01:36:04,150 +an environment variable that's settable, + +2021 +01:36:04,150 --> 01:36:07,573 +it only sets it in the +Views that you set it on. + +2022 +01:36:09,605 --> 01:36:10,670 +Let's see this in action + +2023 +01:36:10,670 --> 01:36:12,587 +just to make sure it hasn't broken here. + +2024 +01:36:12,587 --> 01:36:14,030 +All right, so hit "Edit". + +2025 +01:36:14,030 --> 01:36:15,250 +All works good. + +2026 +01:36:15,250 --> 01:36:16,410 +All right, Done. + +2027 +01:36:16,410 --> 01:36:18,980 +So now when we're in edit mode, +we know we're in edit mode + +2028 +01:36:18,980 --> 01:36:20,930 +because this editMode is gonna be set. + +2029 +01:36:20,930 --> 01:36:24,500 +So we want to change +this from being a Text + +2030 +01:36:24,500 --> 01:36:26,883 +to being a TextField, essentially. + +2031 +01:36:27,940 --> 01:36:29,950 +So right here is where we have our Text. + +2032 +01:36:29,950 --> 01:36:34,950 +I actually created a nice little +struct called EditableText. + +2033 +01:36:36,250 --> 01:36:39,853 +So let's grab that it's +right here and drag this in. + +2034 +01:36:40,690 --> 01:36:41,663 +Copy it in. + +2035 +01:36:42,530 --> 01:36:45,060 +We're not gonna look at +EditableText very much, + +2036 +01:36:45,060 --> 01:36:46,970 +but at its heart, it's a TextField. + +2037 +01:36:46,970 --> 01:36:50,520 +It's doing some other +kinda tricky things to be, + +2038 +01:36:50,520 --> 01:36:54,330 +to nicely switch out when +it's editable or not editable. + +2039 +01:36:54,330 --> 01:36:59,057 +And it takes an additional +argument, which is isEditing. + +2040 +01:36:59,920 --> 01:37:03,130 +And this isEditing just is whether or not + +2041 +01:37:03,130 --> 01:37:05,350 +this EditableText is currently editing. + +2042 +01:37:05,350 --> 01:37:09,073 +And for us, that is our +self.editMode.isEditing. + +2043 +01:37:11,175 --> 01:37:13,830 +And if that's this +editMode, if this is editing + +2044 +01:37:13,830 --> 01:37:16,600 +this is just a var that +looks at this inactive State + +2045 +01:37:16,600 --> 01:37:19,707 +or active State and tells you +where, whether it's editing. + +2046 +01:37:19,707 --> 01:37:24,690 +And it also takes a nice +little closure at the end + +2047 +01:37:24,690 --> 01:37:27,760 +anytime this EditableText changes. + +2048 +01:37:27,760 --> 01:37:31,600 +So the user changed it, then +it calls this closure for you + +2049 +01:37:31,600 --> 01:37:32,950 +with the Text. + +2050 +01:37:32,950 --> 01:37:34,440 +And in our case, this is the name + +2051 +01:37:34,440 --> 01:37:35,810 +so I'm calling this argument name, + +2052 +01:37:35,810 --> 01:37:37,840 +could be called text or whatever you want. + +2053 +01:37:37,840 --> 01:37:39,510 +And when that happens, of course, + +2054 +01:37:39,510 --> 01:37:42,150 +I want to set the name in our store + +2055 +01:37:43,330 --> 01:37:44,403 +for that document. + +2056 +01:37:46,520 --> 01:37:47,493 +Go through that, so +I'm just replacing this + +2057 +01:37:47,493 --> 01:37:49,133 +with this little EditableText. + +2058 +01:37:50,450 --> 01:37:52,113 +So let's see if this works. + +2059 +01:37:54,380 --> 01:37:58,840 +Right, here we go, we're +gonna edit, and click, + +2060 +01:37:58,840 --> 01:38:00,540 +woo, look at that. + +2061 +01:38:00,540 --> 01:38:03,363 +Hello, hello, hello there. + +2062 +01:38:04,840 --> 01:38:05,673 +Oops. + +2063 +01:38:08,600 --> 01:38:09,640 +And now we're done. + +2064 +01:38:09,640 --> 01:38:12,713 +And this is "Hello There" +is the name of that. + +2065 +01:38:13,850 --> 01:38:16,270 +Let me change this "Untitled" right here. + +2066 +01:38:16,270 --> 01:38:21,163 +Edit, call this maybe our "Barn". + +2067 +01:38:25,140 --> 01:38:28,100 +Now, this is automatically +keeping it in alphabetical order + +2068 +01:38:28,100 --> 01:38:29,870 +'cause that's, the store does that. + +2069 +01:38:29,870 --> 01:38:33,457 +So this is a barn, so maybe +we'll put our barn over here. + +2070 +01:38:35,180 --> 01:38:37,313 +It's telling us what to do, that's good. + +2071 +01:38:37,313 --> 01:38:40,490 +Go over here, back to the barn. + +2072 +01:38:40,490 --> 01:38:42,170 +Here's the barn. + +2073 +01:38:42,170 --> 01:38:43,954 +Low res barn here. + +2074 +01:38:43,954 --> 01:38:47,510 +Copy, back and paste. + +2075 +01:38:47,510 --> 01:38:49,210 +And yes, we do wanna paste it. + +2076 +01:38:49,210 --> 01:38:51,670 +There it is, so that's our barn. + +2077 +01:38:51,670 --> 01:38:53,130 +There's our "Hello There". + +2078 +01:38:53,130 --> 01:38:54,693 +There's an untitled document. + +2079 +01:38:55,570 --> 01:38:56,403 +Woo! + +2080 +01:38:57,280 --> 01:39:00,087 +So we built a pretty +functional little app here. + +2081 +01:39:00,087 --> 01:39:03,503 +That's pretty easy to +use, direct manipulation. + +2082 +01:39:04,420 --> 01:39:07,810 +And a lot of this we've +done by presenting Views + +2083 +01:39:07,810 --> 01:39:10,930 +in different ways, whether +it's sheets or popovers. + +2084 +01:39:10,930 --> 01:39:14,370 +By the way, let's take, +right here we are in iPhone, + +2085 +01:39:14,370 --> 01:39:16,920 +let's go back and make sure +we haven't broken anything + +2086 +01:39:16,920 --> 01:39:18,693 +on our iPad over here. + +2087 +01:39:19,680 --> 01:39:23,050 +We did an awful lot of work +over there on the iPhone. + +2088 +01:39:23,050 --> 01:39:26,503 +So I sure hope this +still looks good on iPad. + +2089 +01:39:27,410 --> 01:39:30,610 +Whoa, so actually, this is interesting, + +2090 +01:39:30,610 --> 01:39:33,290 +this looks quite a bit different here. + +2091 +01:39:33,290 --> 01:39:36,670 +You can see that our chooser +is on screen with this space, + +2092 +01:39:36,670 --> 01:39:39,140 +which is actually our documents. + +2093 +01:39:39,140 --> 01:39:42,140 +So we could see both at +the same time on the iPad. + +2094 +01:39:42,140 --> 01:39:45,260 +And as we've seen, SwiftUI will adapt + +2095 +01:39:45,260 --> 01:39:48,010 +whatever user interface we've declared + +2096 +01:39:48,010 --> 01:39:50,560 +to the device that it's on. + +2097 +01:39:50,560 --> 01:39:54,730 +So it's not necessarily the +perfect UI here for iPad, + +2098 +01:39:54,730 --> 01:39:57,560 +I'm not sure I need to be able +to see my document chooser + +2099 +01:39:57,560 --> 01:40:00,340 +on screen at all times, +might wanna put that + +2100 +01:40:00,340 --> 01:40:04,650 +document chooser in a +popover even on iPad. + +2101 +01:40:04,650 --> 01:40:06,430 +But we can certainly see +that it did something + +2102 +01:40:06,430 --> 01:40:08,860 +quite sensible as the default here. + +2103 +01:40:08,860 --> 01:40:11,460 +Now, you can see that +I've already loaded up + +2104 +01:40:11,460 --> 01:40:13,640 +a couple of documents +here, "Barn" and "House" + +2105 +01:40:13,640 --> 01:40:15,290 +to make this go a little bit quicker. + +2106 +01:40:15,290 --> 01:40:16,373 +So let's take a look and make sure + +2107 +01:40:16,373 --> 01:40:17,650 +that we haven't done anything + +2108 +01:40:17,650 --> 01:40:20,293 +to break our palette editor here. + +2109 +01:40:21,460 --> 01:40:24,280 +Hmm, it appears to be working here, + +2110 +01:40:24,280 --> 01:40:28,440 +but I think this looked +better as a popover. + +2111 +01:40:28,440 --> 01:40:32,030 +So let's jump back over +to our PaletteChooser + +2112 +01:40:32,030 --> 01:40:35,393 +and change this sheet +back to being a popover. + +2113 +01:40:39,570 --> 01:40:44,360 +In our House document up here, +let's zoom in a little bit. + +2114 +01:40:44,360 --> 01:40:45,790 +And let's click. + +2115 +01:40:45,790 --> 01:40:49,103 +Huh, I'm tapping here on this keyboard. + +2116 +01:40:50,451 --> 01:40:52,440 +It's not working, I'm clicking on this. + +2117 +01:40:52,440 --> 01:40:55,610 +Why is this not working to click on this? + +2118 +01:40:55,610 --> 01:40:58,780 +Well, the problem is that +we're zoomed way out, + +2119 +01:40:58,780 --> 01:41:02,270 +and even though we clip +to draw in this space, + +2120 +01:41:02,270 --> 01:41:05,960 +our View is still large and +when we're tapping here, + +2121 +01:41:05,960 --> 01:41:08,290 +trying to tap on this keyboard + +2122 +01:41:08,290 --> 01:41:10,930 +our View happens to be in front. + +2123 +01:41:10,930 --> 01:41:12,100 +And so it's intercepting, + +2124 +01:41:12,100 --> 01:41:12,993 +even though it's not drawing up here, + +2125 +01:41:12,993 --> 01:41:16,240 +it's still intercepting the taps. + +2126 +01:41:16,240 --> 01:41:17,910 +So how do we fix that? + +2127 +01:41:17,910 --> 01:41:21,380 +How do we make it so that +this doesn't get in front. + +2128 +01:41:21,380 --> 01:41:24,160 +You can control which Views are in front + +2129 +01:41:24,160 --> 01:41:26,840 +using something called +the zIndex modifier. + +2130 +01:41:26,840 --> 01:41:29,560 +So let's go back to our +document View over here. + +2131 +01:41:29,560 --> 01:41:31,170 +And we're gonna make it so that + +2132 +01:41:31,170 --> 01:41:35,580 +our whole GeometryReader +here is kept in the back + +2133 +01:41:35,580 --> 01:41:39,670 +by setting its zIndex to minus one. + +2134 +01:41:39,670 --> 01:41:41,640 +The default zIndex is zero. + +2135 +01:41:41,640 --> 01:41:43,967 +So all of our other Views +like our palette up here + +2136 +01:41:43,967 --> 01:41:45,170 +are all gonna be zero, + +2137 +01:41:45,170 --> 01:41:46,880 +they're gonna be closer to the front. + +2138 +01:41:46,880 --> 01:41:50,270 +And our GeometryReader +with all of the stuff + +2139 +01:41:50,270 --> 01:41:52,327 +in our document is gonna +be closer to the back. + +2140 +01:41:52,327 --> 01:41:56,170 +And so this simple reordering of Views + +2141 +01:41:56,170 --> 01:41:57,210 +is gonna make this work. + +2142 +01:41:57,210 --> 01:42:00,520 +So here we go, we have a large +image, it's overlapping it + +2143 +01:42:00,520 --> 01:42:04,213 +and it still opens our +palette editor right here. + +2144 +01:42:05,290 --> 01:42:08,630 +So this all started when we +changed this back to popover + +2145 +01:42:08,630 --> 01:42:09,870 +from being a sheet, + +2146 +01:42:09,870 --> 01:42:12,593 +and it looks like it's +working great right here. + +2147 +01:42:13,580 --> 01:42:17,640 +But changing this to popover +is that gonna break our iPhone? + +2148 +01:42:17,640 --> 01:42:19,653 +No indeed, let's go take a look. + +2149 +01:42:24,390 --> 01:42:25,233 +Hello there. + +2150 +01:42:26,830 --> 01:42:28,860 +And it still works even those it's, + +2151 +01:42:28,860 --> 01:42:32,100 +obviously, you can't show +a popover on the iPhone, + +2152 +01:42:32,100 --> 01:42:34,380 +but still works just fine. + +2153 +01:42:34,380 --> 01:42:38,190 +All right, so, longest demo of the year. + +2154 +01:42:38,190 --> 01:42:39,560 +Hope you enjoyed that. + +2155 +01:42:39,560 --> 01:42:42,160 +And your homework that's +based on all of this + +2156 +01:42:42,160 --> 01:42:47,160 +is to essentially create this +kind of chooser right here + +2157 +01:42:47,250 --> 01:42:49,790 +that works for Memorize. + +2158 +01:42:49,790 --> 01:42:52,470 +So you're going to have your themes, + +2159 +01:42:52,470 --> 01:42:54,961 +your Memorize themes up here chosen from, + +2160 +01:42:54,961 --> 01:42:56,800 +that when you click, +you're gonna play a game + +2161 +01:42:56,800 --> 01:42:58,093 +based on that theme. + +2162 +01:42:59,210 --> 01:43:00,670 +And of course, you're going to make it + +2163 +01:43:00,670 --> 01:43:02,760 +so that your themes are editable + +2164 +01:43:02,760 --> 01:43:06,690 +with some sort of editor similar to this. + +2165 +01:43:06,690 --> 01:43:09,207 +You can change things like +like the color of the theme, + +2166 +01:43:09,207 --> 01:43:11,410 +the emojis in the theme, +that kind of stuff. + +2167 +01:43:11,410 --> 01:43:12,960 +So you're gonna be doing +something quite similar + +2168 +01:43:12,960 --> 01:43:16,283 +to what we're doing here but +just in Memorize instead. + +2169 +01:43:17,838 --> 01:43:19,080 +So good luck on that homework + +2170 +01:43:19,080 --> 01:43:21,943 +and you know where to find +us if you have questions. + +2171 +01:43:23,000 --> 01:43:26,213 +- [Narrator] For more, please +visit us at stanford.edu. diff --git a/subtitles/en/Lecture 11. Picker b/subtitles/en/Lecture 11. Picker new file mode 100644 index 0000000..6a4f696 --- /dev/null +++ b/subtitles/en/Lecture 11. Picker @@ -0,0 +1,4982 @@ +1 +00:00:00,316 --> 00:00:02,899 +(serene music) + +2 +00:00:04,940 --> 00:00:06,590 +- [Narrator] Stanford University. + +3 +00:00:11,490 --> 00:00:12,510 +- Hello, everyone. + +4 +00:00:12,510 --> 00:00:16,930 +Welcome to one CS193p, spring of 2020. + +5 +00:00:16,930 --> 00:00:20,534 +This is lecture 11, al fresco version. + +6 +00:00:20,534 --> 00:00:23,160 +Here outside to celebrate that + +7 +00:00:23,160 --> 00:00:25,960 +we pretty much covered the +main topics of SwiftUI. + +8 +00:00:25,960 --> 00:00:27,820 +And you should be able now to go off + +9 +00:00:27,820 --> 00:00:29,090 +and do your final project + +10 +00:00:29,090 --> 00:00:30,950 +after you've finished with assignment six, + +11 +00:00:30,950 --> 00:00:34,080 +which you're in the middle +of working on right now. + +12 +00:00:34,080 --> 00:00:35,824 +I'm still gonna have a few more lectures, + +13 +00:00:35,824 --> 00:00:38,340 +although I will not be having +lectures during dead week, + +14 +00:00:38,340 --> 00:00:41,060 +nor am I gonna do a +lecture on Memorial day. + +15 +00:00:41,060 --> 00:00:44,154 +So I believe that leaves us +with three lectures more. + +16 +00:00:44,154 --> 00:00:48,540 +I will try to accelerate those +lectures as much as possible + +17 +00:00:48,540 --> 00:00:49,960 +because they're all gonna be topics + +18 +00:00:49,960 --> 00:00:52,770 +that you might wanna work +on for your final project, + +19 +00:00:52,770 --> 00:00:55,220 +not required, but you +might wanna use them. + +20 +00:00:55,220 --> 00:00:57,400 +And if I wait too long to bring them out, + +21 +00:00:57,400 --> 00:00:58,900 +you won't have time to incorporate 'em + +22 +00:00:58,900 --> 00:00:59,733 +into your final project. + +23 +00:00:59,733 --> 00:01:03,800 +So I'll try to get those out +as soon as I possibly can. + +24 +00:01:03,800 --> 00:01:06,810 +And speaking of your final project, + +25 +00:01:06,810 --> 00:01:09,080 +read the rubric carefully. + +26 +00:01:09,080 --> 00:01:10,610 +And if you have any questions about it, + +27 +00:01:10,610 --> 00:01:14,420 +make sure you ask in the +class forums, questions, + +28 +00:01:14,420 --> 00:01:18,200 +I'm happy to answer and +clarifications, et cetera. + +29 +00:01:18,200 --> 00:01:20,480 +In terms of advice for your final project, + +30 +00:01:20,480 --> 00:01:24,230 +I really recommend doing a +good detailed project proposal. + +31 +00:01:24,230 --> 00:01:25,630 +That's your first deliverable. + +32 +00:01:25,630 --> 00:01:27,360 +It's due on Monday + +33 +00:01:27,360 --> 00:01:30,050 +and we are not gonna be held responsible + +34 +00:01:30,050 --> 00:01:32,060 +if you say you're gonna do +something in that proposal + +35 +00:01:32,060 --> 00:01:33,550 +and you don't end up doing it. + +36 +00:01:33,550 --> 00:01:36,750 +So it's better to suggest +a little too much there + +37 +00:01:36,750 --> 00:01:38,630 +and then come up a little short, + +38 +00:01:38,630 --> 00:01:41,690 +than the opposite, +suggest not quite enough, + +39 +00:01:41,690 --> 00:01:43,620 +you're not sure what you're gonna do + +40 +00:01:43,620 --> 00:01:44,740 +and then you dive into it + +41 +00:01:44,740 --> 00:01:45,704 +and you really haven't thought ahead + +42 +00:01:45,704 --> 00:01:47,730 +and planned out what you're gonna do. + +43 +00:01:47,730 --> 00:01:49,227 +So that's my first piece of advice. + +44 +00:01:49,227 --> 00:01:50,747 +My second piece of advice, + +45 +00:01:50,747 --> 00:01:52,680 +old hackneyed advice + +46 +00:01:52,680 --> 00:01:54,740 +from all your instructors +of your courses here, + +47 +00:01:54,740 --> 00:01:56,990 +which is start early. + +48 +00:01:56,990 --> 00:02:00,620 +Now, this is not just start +early so you have more time, + +49 +00:02:00,620 --> 00:02:02,780 +you wanna start early +because as I've said, + +50 +00:02:02,780 --> 00:02:05,280 +maybe even said in this +course, I don't remember, + +51 +00:02:05,280 --> 00:02:08,770 +but programming is like +doing a crossword puzzle. + +52 +00:02:08,770 --> 00:02:11,000 +Even if you're really +good at crossword puzzles, + +53 +00:02:11,000 --> 00:02:12,720 +you'll sometimes get started on one + +54 +00:02:12,720 --> 00:02:14,340 +and you just can't figure it out. + +55 +00:02:14,340 --> 00:02:15,880 +And you're just convinced +there's just no way + +56 +00:02:15,880 --> 00:02:19,840 +I'm gonna get these last four +across and down in the corner + +57 +00:02:19,840 --> 00:02:21,640 +or something like that, it's impossible. + +58 +00:02:21,640 --> 00:02:24,150 +And then you go to sleep +and you wake up next day + +59 +00:02:24,150 --> 00:02:25,260 +and you have your lunch. + +60 +00:02:25,260 --> 00:02:26,659 +And then in the afternoon, +all of a sudden you're like, + +61 +00:02:26,659 --> 00:02:29,810 +oh yeah, I know what 39 down is. + +62 +00:02:29,810 --> 00:02:34,040 +And once you get 39 down, the +whole thing falls into place. + +63 +00:02:34,040 --> 00:02:36,217 +And that's because your subconscious + +64 +00:02:36,217 --> 00:02:39,100 +got a chance to work on +that crossword puzzle. + +65 +00:02:39,100 --> 00:02:40,559 +Your conscious mind is distracted + +66 +00:02:40,559 --> 00:02:42,739 +by a lot of things going on around you. + +67 +00:02:42,739 --> 00:02:44,369 +It's got limited bandwidth. + +68 +00:02:44,369 --> 00:02:47,355 +Your subconscious mind can +sit there and cook on problems + +69 +00:02:47,355 --> 00:02:50,630 +and just come up with the +most amazing solutions. + +70 +00:02:50,630 --> 00:02:52,920 +And so let your subconscious work. + +71 +00:02:52,920 --> 00:02:54,250 +Work on your final project, + +72 +00:02:54,250 --> 00:02:56,670 +even if it's just 20 minutes in a day + +73 +00:02:56,670 --> 00:02:58,160 +to touch base with it + +74 +00:02:58,160 --> 00:03:01,547 +and remind your subconscious +mind what's going on. + +75 +00:03:01,547 --> 00:03:02,850 +You have a really good chance + +76 +00:03:02,850 --> 00:03:05,848 +that the next day you're +gonna get 39 down, okay? + +77 +00:03:05,848 --> 00:03:08,110 +Or the equivalent thereof in programming. + +78 +00:03:08,110 --> 00:03:09,460 +So I really recommend that. + +79 +00:03:10,380 --> 00:03:13,200 +All right, big demo again today, + +80 +00:03:13,200 --> 00:03:14,770 +covering another topic + +81 +00:03:14,770 --> 00:03:16,780 +that's not required +for your final project, + +82 +00:03:16,780 --> 00:03:17,980 +but it's likely most of you + +83 +00:03:17,980 --> 00:03:19,343 +are actually going to +want to use this thing + +84 +00:03:19,343 --> 00:03:20,700 +called a Picker. + +85 +00:03:20,700 --> 00:03:22,823 +So let's jump into that right now. + +86 +00:03:24,540 --> 00:03:27,400 +This demo is mostly about Picker, + +87 +00:03:27,400 --> 00:03:30,210 +but we're going to do it in +the context of a new app, + +88 +00:03:30,210 --> 00:03:32,387 +not Memorize or Emoji Art + +89 +00:03:32,387 --> 00:03:34,890 +and this app, which is called Enroute, + +90 +00:03:34,890 --> 00:03:36,980 +and I'm gonna show it to you in a moment + +91 +00:03:36,980 --> 00:03:40,040 +is also gonna be the basis +for next week's demos. + +92 +00:03:40,040 --> 00:03:42,640 +So today we're not just +learning about Picker, + +93 +00:03:42,640 --> 00:03:45,120 +we're learning a little bit +about how Enroute works, + +94 +00:03:45,120 --> 00:03:47,840 +so when we do our stuff next week, + +95 +00:03:47,840 --> 00:03:50,370 +we'll have a shared knowledge of it. + +96 +00:03:50,370 --> 00:03:53,480 +Another difference today is +with Emoji Art and Memorize + +97 +00:03:53,480 --> 00:03:56,130 +we started those +applications from scratch, + +98 +00:03:56,130 --> 00:03:59,160 +but this one I'm starting +with a working code + +99 +00:03:59,160 --> 00:03:59,993 +that does certain amount +of functionality already, + +100 +00:03:59,993 --> 00:04:03,807 +and we're gonna add functionality to it. + +101 +00:04:03,807 --> 00:04:05,410 +And I'm doing that because + +102 +00:04:05,410 --> 00:04:08,640 +this application fetches some +information from the internet + +103 +00:04:08,640 --> 00:04:10,530 +and so the code to do that + +104 +00:04:10,530 --> 00:04:13,404 +is not something that +really is within the scope + +105 +00:04:13,404 --> 00:04:15,180 +of this class. + +106 +00:04:15,180 --> 00:04:17,360 +You're certainly welcome to look at it, + +107 +00:04:17,360 --> 00:04:19,460 +see if you can understand +it, what it's doing. + +108 +00:04:19,460 --> 00:04:22,770 +It's not that complex and it's +all pretty much demo-ware, + +109 +00:04:22,770 --> 00:04:24,843 +just something I put +together over the weekend + +110 +00:04:24,843 --> 00:04:26,722 +for this demo. + +111 +00:04:26,722 --> 00:04:29,330 +But I don't really wanna +go through that in detail. + +112 +00:04:29,330 --> 00:04:31,550 +Instead, I wanna focus on some features + +113 +00:04:31,550 --> 00:04:34,640 +that will really help you +with your final project + +114 +00:04:34,640 --> 00:04:36,333 +like today, Picker. + +115 +00:04:37,400 --> 00:04:39,920 +So let's review this app called Enroute. + +116 +00:04:39,920 --> 00:04:42,470 +I'm gonna run it so you +can see what it looks like. + +117 +00:04:43,607 --> 00:04:48,120 +Enroute essentially uses an API + +118 +00:04:48,120 --> 00:04:49,470 +that's available on the internet + +119 +00:04:49,470 --> 00:04:51,340 +from a company called FlightAware, + +120 +00:04:51,340 --> 00:04:53,160 +and you can see that +it's actually loading up + +121 +00:04:53,160 --> 00:04:54,990 +some flight information here. + +122 +00:04:54,990 --> 00:04:58,610 +In this case, it's loading up +flights that are in the air + +123 +00:04:58,610 --> 00:05:02,390 +enroute to San Francisco +International KSFO. + +124 +00:05:02,390 --> 00:05:05,630 +That's its little airport code there. + +125 +00:05:05,630 --> 00:05:08,380 +And you can see that it's +telling us this SkyWest flight + +126 +00:05:08,380 --> 00:05:10,863 +arrives today at 11:42, +that's in two minutes, + +127 +00:05:10,863 --> 00:05:12,432 +it's coming from Los Angeles. + +128 +00:05:12,432 --> 00:05:14,320 +And it's telling us +about all these flights, + +129 +00:05:14,320 --> 00:05:19,320 +different airlines, different +origin airports, et cetera. + +130 +00:05:19,320 --> 00:05:23,020 +And our goal today with Picker +is we wanna add some UI. + +131 +00:05:23,020 --> 00:05:25,190 +I'm gonna put a little +Button in the corner here + +132 +00:05:25,190 --> 00:05:26,117 +called filter + +133 +00:05:26,117 --> 00:05:28,003 +And it's gonna bring up a modal sheet + +134 +00:05:28,003 --> 00:05:31,430 +that lets us filter these results + +135 +00:05:31,430 --> 00:05:34,240 +by for example, where it's coming from + +136 +00:05:34,240 --> 00:05:37,840 +or which airline or whether +it's in the air or not, + +137 +00:05:37,840 --> 00:05:40,470 +because there are flights +coming to San Francisco + +138 +00:05:40,470 --> 00:05:42,850 +that are scheduled to +arrive at certain times, + +139 +00:05:42,850 --> 00:05:44,520 +but maybe they haven't taken off. + +140 +00:05:44,520 --> 00:05:46,920 +They might be scheduled to take off later, + +141 +00:05:46,920 --> 00:05:48,960 +or they might be delayed or whatever. + +142 +00:05:48,960 --> 00:05:50,680 +I'm not currently showing any of those. + +143 +00:05:50,680 --> 00:05:53,590 +All these flights you see +right here are in the air, + +144 +00:05:53,590 --> 00:05:56,230 +actually flying to San +Francisco at this very moment. + +145 +00:05:56,230 --> 00:05:58,070 +And this is real data +coming from FlightAware. + +146 +00:05:58,070 --> 00:06:02,020 +FlightAware is not a free API to use. + +147 +00:06:02,020 --> 00:06:03,580 +It's quite inexpensive. + +148 +00:06:03,580 --> 00:06:05,535 +So hey, if you have a few bucks, + +149 +00:06:05,535 --> 00:06:07,761 +you can head over to FlightAware + +150 +00:06:07,761 --> 00:06:09,530 +and sign up and get your own key. + +151 +00:06:09,530 --> 00:06:11,640 +And so then when you run this demo code, + +152 +00:06:11,640 --> 00:06:15,450 +you can get live data like +I'm getting right here. + +153 +00:06:15,450 --> 00:06:19,100 +Or I also am gonna provide +some simulated data + +154 +00:06:19,100 --> 00:06:20,020 +so that those of you + +155 +00:06:20,020 --> 00:06:21,830 +who don't wanna go to +FlightAware and sign up + +156 +00:06:21,830 --> 00:06:23,540 +you'll get some simulated data + +157 +00:06:23,540 --> 00:06:25,630 +from over the weekend basically. + +158 +00:06:25,630 --> 00:06:26,958 +It only has a couple of airports, + +159 +00:06:26,958 --> 00:06:30,160 +San Francisco and Las Vegas, I think, + +160 +00:06:30,160 --> 00:06:32,830 +but it'll let you at least see the code + +161 +00:06:32,830 --> 00:06:35,940 +and get your Picker working +and things like that. + +162 +00:06:35,940 --> 00:06:39,500 +Let's talk a little bit +about how Enroute is built, + +163 +00:06:39,500 --> 00:06:40,930 +how this app works. + +164 +00:06:40,930 --> 00:06:42,880 +So this View right here +that you're seeing, + +165 +00:06:42,880 --> 00:06:46,660 +this list of flights +is just a single View. + +166 +00:06:46,660 --> 00:06:49,200 +It's the only View file that we have + +167 +00:06:49,200 --> 00:06:50,280 +in the whole app right here, + +168 +00:06:50,280 --> 00:06:54,220 +this FlightsEnrouteView.swift. + +169 +00:06:54,220 --> 00:06:55,550 +And so let's go through this. + +170 +00:06:55,550 --> 00:06:59,210 +You can see it's actually +quite a simple little View, + +171 +00:06:59,210 --> 00:07:00,484 +really not much to it here. + +172 +00:07:00,484 --> 00:07:03,500 +At the top level there's +this FlightsEnrouteView. + +173 +00:07:03,500 --> 00:07:05,200 +It's just a NavigationView. + +174 +00:07:05,200 --> 00:07:07,557 +You did notice that our app over here + +175 +00:07:07,557 --> 00:07:10,340 +is definitely in a NavigationView, + +176 +00:07:10,340 --> 00:07:12,530 +even though we don't click +on these and navigate, + +177 +00:07:12,530 --> 00:07:15,130 +one day maybe we would, but we don't now. + +178 +00:07:15,130 --> 00:07:17,210 +You're still getting the +title of NavigationView + +179 +00:07:17,210 --> 00:07:19,200 +and if we had some buttons up here, + +180 +00:07:19,200 --> 00:07:21,510 +like we're gonna put that +filter button up there + +181 +00:07:21,510 --> 00:07:23,210 +we are getting the benefits + +182 +00:07:23,210 --> 00:07:24,710 +of being a NavigationView here. + +183 +00:07:24,710 --> 00:07:26,650 +And then inside that +navigation is this FlightList. + +184 +00:07:26,650 --> 00:07:29,790 +This FlightList is this View right here. + +185 +00:07:29,790 --> 00:07:32,036 +Another really simple little View. + +186 +00:07:32,036 --> 00:07:34,261 +All it does is have a List + +187 +00:07:34,261 --> 00:07:36,821 +that's ForEach through all the flights + +188 +00:07:36,821 --> 00:07:39,610 +and it uses this FlightListEntry View + +189 +00:07:39,610 --> 00:07:43,880 +to show each of the +things in the flight here. + +190 +00:07:43,880 --> 00:07:46,040 +So this is the FlightListEntry + +191 +00:07:46,040 --> 00:07:49,830 +is showing you all this stuff in each row. + +192 +00:07:49,830 --> 00:07:51,430 +So let's take a look at FlightListEntry, + +193 +00:07:51,430 --> 00:07:53,100 +which is this View right here. + +194 +00:07:53,100 --> 00:07:55,270 +It's also simple little View. + +195 +00:07:55,270 --> 00:07:58,276 +It's just a VStack with +the name of the flight, + +196 +00:07:58,276 --> 00:08:03,276 +like United 245, when it arrives +and where it's coming from. + +197 +00:08:03,620 --> 00:08:04,453 +And that's it. + +198 +00:08:04,453 --> 00:08:05,672 +That's the entirety of FlightListEntry. + +199 +00:08:05,672 --> 00:08:07,540 +All that's happening down here + +200 +00:08:07,540 --> 00:08:10,070 +is where it's calculating +Strings for all those things, + +201 +00:08:10,070 --> 00:08:12,490 +the name, the arrival and the origin. + +202 +00:08:12,490 --> 00:08:14,357 +Now, one thing that's +interesting about FlightListEntry + +203 +00:08:14,357 --> 00:08:18,040 +is it has two ViewModels here. + +204 +00:08:18,040 --> 00:08:19,891 +Each of these ViewModels represent + +205 +00:08:19,891 --> 00:08:23,240 +either all the airports +or all the airlines + +206 +00:08:23,240 --> 00:08:25,300 +that my app knows about. + +207 +00:08:25,300 --> 00:08:26,870 +So as I'm using my app, + +208 +00:08:26,870 --> 00:08:29,922 +it's finding out about more +and more airports and airlines, + +209 +00:08:29,922 --> 00:08:32,260 +and it's asking FlightAware about them. + +210 +00:08:32,260 --> 00:08:34,760 +What's the name of them and where are they + +211 +00:08:34,760 --> 00:08:36,290 +and things like that. + +212 +00:08:36,290 --> 00:08:38,197 +And that information is all coming back. + +213 +00:08:38,197 --> 00:08:42,870 +And these are just ObservableObjects + +214 +00:08:42,870 --> 00:08:44,340 +that when the information changes, + +215 +00:08:44,340 --> 00:08:46,640 +they do, their objectWillChange.send() + +216 +00:08:46,640 --> 00:08:49,460 +and they update and cause +things like this to redraw + +217 +00:08:49,460 --> 00:08:53,340 +with the proper information +of the name of the airline, + +218 +00:08:53,340 --> 00:08:55,840 +or the name of the airport. + +219 +00:08:55,840 --> 00:08:58,200 +So that's all that's going +on here in FlightListEntry. + +220 +00:08:58,200 --> 00:09:00,052 +So this is a View like you're used to + +221 +00:09:00,052 --> 00:09:02,680 +with a ViewModel, has two ViewModels. + +222 +00:09:02,680 --> 00:09:05,180 +It's perfectly fine for a View +to have multiple ViewModels + +223 +00:09:05,180 --> 00:09:06,720 +as we'll see next week. + +224 +00:09:06,720 --> 00:09:07,884 +And it just takes any flight. + +225 +00:09:07,884 --> 00:09:09,150 +One of these FAFlights + +226 +00:09:10,430 --> 00:09:14,120 +and this FAFlight comes +back from FlightAware. + +227 +00:09:14,120 --> 00:09:15,140 +We can take a look at that. + +228 +00:09:15,140 --> 00:09:17,010 +Here's all the code for +FlightAware in here. + +229 +00:09:17,010 --> 00:09:18,165 +You can go look at it later. + +230 +00:09:18,165 --> 00:09:19,489 +But an FAFlight just has things + +231 +00:09:19,489 --> 00:09:21,260 +like the identity of the flight + +232 +00:09:21,260 --> 00:09:22,920 +and what aircraft is being used, + +233 +00:09:22,920 --> 00:09:26,670 +the destination and origin cities, + +234 +00:09:26,670 --> 00:09:27,960 +has some little functions. + +235 +00:09:27,960 --> 00:09:31,150 +Notice that I made FAFlight +to be Codeable and Hashable + +236 +00:09:31,150 --> 00:09:33,090 +and Identifiable and Comparable + +237 +00:09:33,090 --> 00:09:34,646 +and CustomStringConvertible. + +238 +00:09:34,646 --> 00:09:36,750 +So there's a lot of things I made it be. + +239 +00:09:36,750 --> 00:09:39,040 +You know what these things are. + +240 +00:09:39,040 --> 00:09:40,580 +Comparable is an interesting one. + +241 +00:09:40,580 --> 00:09:43,390 +This is the Comparable +protocol right here. + +242 +00:09:43,390 --> 00:09:45,520 +It just lets you compare two things + +243 +00:09:45,520 --> 00:09:46,890 +to see if they're less than. + +244 +00:09:46,890 --> 00:09:48,540 +This is a nice one to implement. + +245 +00:09:48,540 --> 00:09:51,610 +I'm comparing them by arrival dates, + +246 +00:09:51,610 --> 00:09:54,570 +which is how we usually +wanna sort flights. + +247 +00:09:54,570 --> 00:09:55,520 +And one thing that's really nice + +248 +00:09:55,520 --> 00:09:56,970 +about implementing Comparable + +249 +00:09:56,970 --> 00:09:59,220 +is that the Array method sorted + +250 +00:09:59,220 --> 00:10:02,560 +will work on an Array of FAFlights here + +251 +00:10:02,560 --> 00:10:03,678 +without any arguments. + +252 +00:10:03,678 --> 00:10:07,810 +And it's just gonna use +Comparable to compare the flights. + +253 +00:10:07,810 --> 00:10:10,260 +And then this other one up +here, CustomStringConvertible. + +254 +00:10:10,260 --> 00:10:12,160 +Also a very interesting one to implement. + +255 +00:10:12,160 --> 00:10:14,710 +That is this var description. + +256 +00:10:14,710 --> 00:10:17,640 +If you implement +CustomStringConvertible up here + +257 +00:10:17,640 --> 00:10:20,130 +and you provide this var description, + +258 +00:10:20,130 --> 00:10:22,184 +then you can say what happens + +259 +00:10:22,184 --> 00:10:24,956 +when this object, a flight object, + +260 +00:10:24,956 --> 00:10:28,440 +gets put into a String with +backslash, open parentheses + +261 +00:10:28,440 --> 00:10:30,360 +closed parentheses, right? + +262 +00:10:30,360 --> 00:10:33,830 +Normally that shows something +that Swift generates about it, + +263 +00:10:33,830 --> 00:10:35,146 +but you can have it say something + +264 +00:10:35,146 --> 00:10:38,356 +that is more easy for you to understand. + +265 +00:10:38,356 --> 00:10:41,840 +Here I just identify my +flight with identifier + +266 +00:10:41,840 --> 00:10:44,802 +and its departure and arrival +information, et cetera. + +267 +00:10:44,802 --> 00:10:48,783 +So that if I print one of these +FAFlights, it looks nicer. + +268 +00:10:50,230 --> 00:10:51,340 +So that's our FAFlight. + +269 +00:10:51,340 --> 00:10:53,770 +That's essentially what's being drawn + +270 +00:10:53,770 --> 00:10:56,330 +in each of those FlightList entries. + +271 +00:10:56,330 --> 00:10:58,850 +If we back up here to the FlightList, + +272 +00:10:58,850 --> 00:11:01,350 +so this is the entire list over here. + +273 +00:11:01,350 --> 00:11:04,300 +It's this View that is this whole list + +274 +00:11:04,300 --> 00:11:05,525 +including all of these things, + +275 +00:11:05,525 --> 00:11:08,240 +it has a ViewModel as well, FlightFetcher, + +276 +00:11:08,240 --> 00:11:09,500 +which is a different thing. + +277 +00:11:09,500 --> 00:11:11,300 +Now FlightFetcher is a +very simple ViewModel. + +278 +00:11:11,300 --> 00:11:12,766 +Let's take a look at it. + +279 +00:11:12,766 --> 00:11:16,068 +It essentially takes something +called a FlightSearch, + +280 +00:11:16,068 --> 00:11:20,030 +which are search parameters for +the list of flights to show. + +281 +00:11:20,030 --> 00:11:21,820 +And this FlightSearch + +282 +00:11:21,820 --> 00:11:24,339 +is a simple little struct right here + +283 +00:11:24,339 --> 00:11:27,640 +that just has the destination +airport, origin airport, + +284 +00:11:27,640 --> 00:11:29,290 +the airline, inTheAir. + +285 +00:11:29,290 --> 00:11:30,870 +If you set these things, + +286 +00:11:30,870 --> 00:11:32,850 +then the only thing it'll show in the list + +287 +00:11:32,850 --> 00:11:35,010 +is the things that match this. + +288 +00:11:35,010 --> 00:11:37,350 +Of course destination would be like KSFO. + +289 +00:11:37,350 --> 00:11:39,390 +So the list is showing thing for KSFO. + +290 +00:11:39,390 --> 00:11:41,906 +If I specified an origin or an airline, + +291 +00:11:41,906 --> 00:11:45,940 +then would only show me +flights to SFO from that origin + +292 +00:11:45,940 --> 00:11:48,540 +or that are flying with that airline. + +293 +00:11:48,540 --> 00:11:50,429 +And inTheAir is the thing that says + +294 +00:11:50,429 --> 00:11:52,690 +whether or not we're showing only flights + +295 +00:11:52,690 --> 00:11:53,870 +that are in the air or not. + +296 +00:11:53,870 --> 00:11:55,210 +So this little struct + +297 +00:11:55,210 --> 00:11:58,410 +just essentially defines +what search we're doing. + +298 +00:11:58,410 --> 00:12:01,144 +So FlightFetcher, this +ViewModel, ObservableObject + +299 +00:12:01,144 --> 00:12:03,010 +takes one of those FlightSearches + +300 +00:12:03,010 --> 00:12:05,640 +and you can change the +FlightSearch at any time. + +301 +00:12:05,640 --> 00:12:08,340 +It makes this var +available that you can set + +302 +00:12:08,340 --> 00:12:09,173 +and anytime it changes, + +303 +00:12:09,173 --> 00:12:11,883 +it goes out to FlightAware and +starts fetching the flight. + +304 +00:12:11,883 --> 00:12:13,340 +It fetches it immediately + +305 +00:12:13,340 --> 00:12:14,630 +and then it continues to fetch it + +306 +00:12:14,630 --> 00:12:18,010 +every certain amount of +time, 30 seconds configurable + +307 +00:12:18,010 --> 00:12:19,190 +what you wanna do. + +308 +00:12:19,190 --> 00:12:20,402 +And then as the information comes back, + +309 +00:12:20,402 --> 00:12:24,410 +it just pops it into +this Array of FAFlights, + +310 +00:12:24,410 --> 00:12:26,637 +those FAFlight things we looked at, + +311 +00:12:26,637 --> 00:12:29,150 +and it's just showing +you the latest result + +312 +00:12:29,150 --> 00:12:30,650 +and it's @Published. + +313 +00:12:30,650 --> 00:12:32,627 +So of course, every time +more results come in, + +314 +00:12:32,627 --> 00:12:35,269 +this thing does its +objectWillChange.send(), + +315 +00:12:35,269 --> 00:12:39,160 +and our View like this +FlightList over here + +316 +00:12:39,160 --> 00:12:41,140 +is gonna redraw itself. + +317 +00:12:41,140 --> 00:12:43,556 +You can see that I have +this little computed var + +318 +00:12:43,556 --> 00:12:45,390 +in my FlightList of flights, + +319 +00:12:45,390 --> 00:12:46,680 +which is an Array of FAFlight. + +320 +00:12:46,680 --> 00:12:49,160 +That's just my ViewModel's latest. + +321 +00:12:49,160 --> 00:12:52,060 +It's giving me the latest +flights from my ViewModel. + +322 +00:12:52,060 --> 00:12:53,550 +And that's how I'm able +to do this ForEach. + +323 +00:12:53,550 --> 00:12:55,274 +So I'm just going through the flights. + +324 +00:12:55,274 --> 00:12:58,590 +Notice I'm using their ident, +their identity of the flight, + +325 +00:12:58,590 --> 00:13:03,590 +like SWK456 would be the +identifier of some flight + +326 +00:13:04,780 --> 00:13:06,900 +and I'm using it to go through + +327 +00:13:06,900 --> 00:13:09,000 +and put those FlightList entries together. + +328 +00:13:10,180 --> 00:13:13,460 +All right, so super simple little View. + +329 +00:13:13,460 --> 00:13:16,640 +Not much to know about here. + +330 +00:13:16,640 --> 00:13:19,560 +Most of the guts of this +program is over here + +331 +00:13:19,560 --> 00:13:21,660 +in this FlightAware code right here + +332 +00:13:21,660 --> 00:13:22,680 +that's doing the fetching. + +333 +00:13:22,680 --> 00:13:25,427 +Again you can go take a +look at that if you want. + +334 +00:13:25,427 --> 00:13:28,560 +We don't really even look +at any of it in our code, + +335 +00:13:28,560 --> 00:13:29,830 +except for this FAFlight. + +336 +00:13:29,830 --> 00:13:31,680 +We're obviously looking at the flights + +337 +00:13:31,680 --> 00:13:33,023 +to see their information. + +338 +00:13:34,530 --> 00:13:37,260 +The airport ViewModel, +this all airport ViewModel, + +339 +00:13:37,260 --> 00:13:41,100 +notice it's a shared +instance of the ViewModel. + +340 +00:13:41,100 --> 00:13:43,387 +That's perfectly fine for +one ViewModel to be shared + +341 +00:13:43,387 --> 00:13:44,220 +by many Views. + +342 +00:13:44,220 --> 00:13:46,820 +They're all looking at +the same all airports. + +343 +00:13:46,820 --> 00:13:48,710 +So we can have a shared one here + +344 +00:13:48,710 --> 00:13:51,707 +and it can give you the codes +of all the airports it knows, + +345 +00:13:51,707 --> 00:13:54,280 +and then also you can +use a subscript on it + +346 +00:13:54,280 --> 00:13:56,090 +with giving it to certain airport, + +347 +00:13:56,090 --> 00:13:57,840 +to get the info that comes back. + +348 +00:13:57,840 --> 00:14:00,750 +This airport info is +down here and FlightAware + +349 +00:14:00,750 --> 00:14:03,200 +it's what comes back from FlightAware. + +350 +00:14:03,200 --> 00:14:04,980 +Just things like the name of the airport + +351 +00:14:04,980 --> 00:14:07,840 +and where it's located, things like that. + +352 +00:14:07,840 --> 00:14:09,147 +And similar one for airlines here, + +353 +00:14:09,147 --> 00:14:11,110 +just another ObservableObject. + +354 +00:14:11,110 --> 00:14:12,230 +Lets you get all the airline info. + +355 +00:14:12,230 --> 00:14:15,852 +So we only use these few Models here + +356 +00:14:15,852 --> 00:14:17,710 +when we want to find out information + +357 +00:14:17,710 --> 00:14:19,870 +about airports and +airlines, which is rare. + +358 +00:14:19,870 --> 00:14:21,186 +Like we're doing it down here. + +359 +00:14:21,186 --> 00:14:22,489 +Of course, in our FlightListEntry, + +360 +00:14:22,489 --> 00:14:25,430 +we wanna find out the origin airport. + +361 +00:14:25,430 --> 00:14:29,187 +We're using this allAirports +here to find out what that is + +362 +00:14:29,187 --> 00:14:31,260 +and the airline that we're flying on + +363 +00:14:31,260 --> 00:14:33,850 +obviously we're going to get its name here + +364 +00:14:33,850 --> 00:14:37,270 +in the name of the flight +that we have right here, + +365 +00:14:37,270 --> 00:14:40,700 +like United 2828, American Airlines 2248. + +366 +00:14:40,700 --> 00:14:42,390 +We wanna put the name of the airline. + +367 +00:14:42,390 --> 00:14:43,690 +So we can do that as well. + +368 +00:14:45,340 --> 00:14:49,007 +Okay, so now that's all there +is to know about Enroute. + +369 +00:14:49,007 --> 00:14:50,748 +You know how Enroute works. + +370 +00:14:50,748 --> 00:14:55,550 +And what we're gonna do today +is add a little filter UI + +371 +00:14:55,550 --> 00:14:58,420 +so that we can filter through this list. + +372 +00:14:58,420 --> 00:15:00,460 +And we're gonna need a Picker to do that + +373 +00:15:00,460 --> 00:15:03,530 +'cause we're gonna be picking +airports, picking airlines, + +374 +00:15:03,530 --> 00:15:04,363 +things like that. + +375 +00:15:04,363 --> 00:15:06,013 +Picker is great for that. + +376 +00:15:06,013 --> 00:15:07,583 +This is also a great opportunity + +377 +00:15:07,583 --> 00:15:12,060 +to review modal sheets, how +we put a modal sheet up. + +378 +00:15:12,060 --> 00:15:14,100 +So let's first of all, just put the code + +379 +00:15:14,100 --> 00:15:16,430 +in our base Enroute View here + +380 +00:15:16,430 --> 00:15:18,460 +that adds a little filter button + +381 +00:15:18,460 --> 00:15:20,744 +to the upper right corner of it. + +382 +00:15:20,744 --> 00:15:22,777 +And then use that filter button + +383 +00:15:22,777 --> 00:15:24,670 +will bring up this modal sheet. + +384 +00:15:24,670 --> 00:15:25,930 +So this is all review. + +385 +00:15:25,930 --> 00:15:27,280 +We already know how to do this. + +386 +00:15:27,280 --> 00:15:31,990 +I'm gonna add that filter +Button as a navigationBarItem. + +387 +00:15:31,990 --> 00:15:34,750 +I'm gonna put it on the +trailing side actually. + +388 +00:15:34,750 --> 00:15:35,930 +I'm just gonna call it filter. + +389 +00:15:35,930 --> 00:15:37,800 +That's gonna be the name of my Button. + +390 +00:15:37,800 --> 00:15:41,360 +It's just gonna be a little +computed var down here + +391 +00:15:41,360 --> 00:15:42,405 +that's some View. + +392 +00:15:42,405 --> 00:15:46,803 +We'll have it return a Button +that says filter on it. + +393 +00:15:46,803 --> 00:15:50,410 +And inside here, when +the Button is clicked, + +394 +00:15:50,410 --> 00:15:53,030 +we're just going to set some boolean var + +395 +00:15:53,030 --> 00:15:55,410 +like showFilter = true. + +396 +00:15:55,410 --> 00:15:58,210 +Just want to have to have a +little bit of State for that. + +397 +00:15:58,210 --> 00:16:02,600 +Private var showFilter starts out false. + +398 +00:16:02,600 --> 00:16:04,430 +And when we set this Bool to true, + +399 +00:16:04,430 --> 00:16:06,610 +we're gonna have a modal sheet come up. + +400 +00:16:06,610 --> 00:16:09,130 +So we can say .sheet, right? + +401 +00:16:09,130 --> 00:16:12,430 +And we know that .sheet +takes this isPresented, + +402 +00:16:12,430 --> 00:16:17,430 +which is a Binding, +remember to this showFilter + +403 +00:16:17,920 --> 00:16:20,830 +so that whenever this Bool is set by us, + +404 +00:16:20,830 --> 00:16:22,620 +this will appear, + +405 +00:16:22,620 --> 00:16:25,520 +but also anytime the sheet is dismissed, + +406 +00:16:25,520 --> 00:16:28,053 +this will be set by the +sheet back to false. + +407 +00:16:29,580 --> 00:16:32,560 +Let's just put a Text +"Filter" on there for now. + +408 +00:16:32,560 --> 00:16:33,393 +the modal sheet + +409 +00:16:33,393 --> 00:16:35,950 +we're just gonna have it say +the word "Filter" on there + +410 +00:16:35,950 --> 00:16:38,780 +just to make sure our UI is working. + +411 +00:16:38,780 --> 00:16:39,850 +So let's take a look at this. + +412 +00:16:39,850 --> 00:16:42,020 +This hopefully should +add this filter button. + +413 +00:16:42,020 --> 00:16:42,989 +There it is up in the corner. + +414 +00:16:42,989 --> 00:16:44,857 +We've clicked filter. (cheers) + +415 +00:16:44,857 --> 00:16:45,950 +You got filter. + +416 +00:16:45,950 --> 00:16:49,120 +So this is where we're going +to put our UI with some Pickers + +417 +00:16:49,120 --> 00:16:51,730 +to pick the destination airport, +pick the origin airport, + +418 +00:16:51,730 --> 00:16:52,912 +pick the airline. + +419 +00:16:52,912 --> 00:16:55,200 +We're gonna put that all in here. + +420 +00:16:55,200 --> 00:16:56,969 +And then when we dismiss that, + +421 +00:16:56,969 --> 00:16:59,680 +it's going to update this whole thing + +422 +00:16:59,680 --> 00:17:03,743 +to show us just those airlines +or origins, et cetera. + +423 +00:17:05,570 --> 00:17:06,403 +How are we gonna do that? + +424 +00:17:06,403 --> 00:17:10,660 +We obviously need some UI to +go here, not Text("Filter"). + +425 +00:17:10,660 --> 00:17:14,920 +We want it to be something +like FilterFlights, + +426 +00:17:14,920 --> 00:17:15,796 +I'm gonna call it, + +427 +00:17:15,796 --> 00:17:20,796 +and it's going to have to take +our little FlightSearch here. + +428 +00:17:22,170 --> 00:17:24,573 +Okay, remember that this FlightSearch + +429 +00:17:25,540 --> 00:17:28,940 +that we have as State in our Enroute View, + +430 +00:17:28,940 --> 00:17:31,120 +it's the thing that's saying +what we're searching with. + +431 +00:17:31,120 --> 00:17:32,178 +'Cause we pass it to the FlightList + +432 +00:17:32,178 --> 00:17:35,320 +and say, hey, Mr. FlightList down here, + +433 +00:17:35,320 --> 00:17:36,942 +please only show me the things with this. + +434 +00:17:36,942 --> 00:17:39,620 +So I'm gonna filter the flights + +435 +00:17:39,620 --> 00:17:43,530 +by essentially editing this +struct, changing this struct. + +436 +00:17:43,530 --> 00:17:46,130 +And as soon as I change this struct, + +437 +00:17:46,130 --> 00:17:47,593 +which is this var right here, + +438 +00:17:48,680 --> 00:17:49,960 +it's gonna redraw + +439 +00:17:49,960 --> 00:17:51,360 +and that's gonna cause the FlightList + +440 +00:17:51,360 --> 00:17:53,024 +to be passed a new FlightSearch + +441 +00:17:53,024 --> 00:17:56,930 +and it's all going to update itself. + +442 +00:17:56,930 --> 00:17:57,911 +So we definitely need to do that. + +443 +00:17:57,911 --> 00:18:01,350 +And then of course, since +this is a presented thing + +444 +00:18:01,350 --> 00:18:05,743 +I'm also going to have +isPresented passed to it as well + +445 +00:18:05,743 --> 00:18:06,912 +by showFilter, + +446 +00:18:06,912 --> 00:18:10,888 +and that will allow this +View, this modal sheet View + +447 +00:18:10,888 --> 00:18:13,760 +to be able to dismiss itself. + +448 +00:18:13,760 --> 00:18:15,820 +Because again, not a big fan + +449 +00:18:15,820 --> 00:18:18,340 +of just having swipe down to dismiss, + +450 +00:18:18,340 --> 00:18:20,880 +be the only way to dismiss things. + +451 +00:18:20,880 --> 00:18:22,400 +It's nice if you have done buttons + +452 +00:18:22,400 --> 00:18:24,343 +and you're gonna see we're +gonna need a Done and a Cancel + +453 +00:18:24,343 --> 00:18:25,423 +for this one. + +454 +00:18:26,310 --> 00:18:28,170 +So let's go create this View, right? + +455 +00:18:28,170 --> 00:18:29,240 +I just made this up. + +456 +00:18:29,240 --> 00:18:31,800 +So we have to go actually +implement this FilterFlights, + +457 +00:18:31,800 --> 00:18:32,850 +That is a View. + +458 +00:18:32,850 --> 00:18:35,033 +So I'm gonna make a new SwiftUI View, + +459 +00:18:36,530 --> 00:18:39,240 +and I'm gonna call it FilterFlights, + +460 +00:18:39,240 --> 00:18:41,030 +make sure that it's in the right place. + +461 +00:18:41,030 --> 00:18:42,860 +Yes, I noticed some of you +are still having a problem + +462 +00:18:42,860 --> 00:18:44,830 +where you're putting +things up here in the blue. + +463 +00:18:44,830 --> 00:18:47,212 +We want things in the yellow there. + +464 +00:18:47,212 --> 00:18:48,644 +Here's FilterFlight. + +465 +00:18:48,644 --> 00:18:50,440 +It says, "Hello, World". + +466 +00:18:50,440 --> 00:18:51,350 +Now we know that our FilterFlights + +467 +00:18:51,350 --> 00:18:55,190 +has a couple of arguments +here, these two Bindings, + +468 +00:18:55,190 --> 00:18:58,440 +so let's put those two +Bindings in right off the bat. + +469 +00:18:58,440 --> 00:19:02,138 +And we know how to pass +Bindings, @Binding to var. + +470 +00:19:02,138 --> 00:19:04,543 +We called one FlightSearch + +471 +00:19:07,174 --> 00:19:11,570 +and that is a Binding to +a FlightSearch struct. + +472 +00:19:11,570 --> 00:19:14,763 +And then we have the +Binding var isPresented, + +473 +00:19:14,763 --> 00:19:17,310 +which is a Binding to a Bool. + +474 +00:19:18,240 --> 00:19:21,012 +So now this FilterFlight +is hooked up to that. + +475 +00:19:21,012 --> 00:19:23,900 +By the way, I'm gonna have +my previews commented out + +476 +00:19:23,900 --> 00:19:25,030 +for now I really don't wanna deal + +477 +00:19:25,030 --> 00:19:27,520 +with having to try and to +pass Bindings in my previews + +478 +00:19:27,520 --> 00:19:29,170 +as we saw can be done. + +479 +00:19:29,170 --> 00:19:31,098 +We can pass constants in here, et cetera. + +480 +00:19:31,098 --> 00:19:33,417 +But we're just gonna ignore that for now + +481 +00:19:33,417 --> 00:19:35,410 +and make this demo go a little quicker + +482 +00:19:35,410 --> 00:19:38,470 +'cause we're really trying +to talk about Pickers here. + +483 +00:19:38,470 --> 00:19:41,630 +We have this FlightSearch passed into us. + +484 +00:19:41,630 --> 00:19:43,130 +Let's make sure that it's actually working + +485 +00:19:43,130 --> 00:19:46,480 +by having our Text here, +say "Filter flights + +486 +00:19:46,480 --> 00:19:51,113 +to our \(flightSearch.destination)". + +487 +00:19:52,220 --> 00:19:56,240 +So if we're properly +Binding this FlightSearch + +488 +00:19:56,240 --> 00:19:57,740 +back to our FlightSearch State + +489 +00:19:58,789 --> 00:20:01,940 +that's in our Enroute's View right here, + +490 +00:20:01,940 --> 00:20:02,860 +then when this print out, + +491 +00:20:02,860 --> 00:20:06,233 +it should print KSFO in this case. + +492 +00:20:09,300 --> 00:20:11,597 +Yes, sorry, FilterFlights flightSearch. + +493 +00:20:13,500 --> 00:20:14,990 +Put the name up here, + +494 +00:20:14,990 --> 00:20:19,650 +because that's the name of +this Binding var right here. + +495 +00:20:19,650 --> 00:20:20,930 +So let's run this. + +496 +00:20:20,930 --> 00:20:24,050 +See if our filter is now +saying FilterFlight to KSFO. + +497 +00:20:24,050 --> 00:20:26,151 +Hopefully it is ready, filter. + +498 +00:20:26,151 --> 00:20:26,984 +(cheers) + +499 +00:20:26,984 --> 00:20:27,817 +FilterFlight to KSFO. + +500 +00:20:27,817 --> 00:20:31,030 +So we are Binding our FlightSearch + +501 +00:20:31,030 --> 00:20:32,860 +to the one that's back in our routes. + +502 +00:20:32,860 --> 00:20:35,171 +And now we're really ready to proceed here + +503 +00:20:35,171 --> 00:20:39,670 +to use some Pickers and +stuff to build that. + +504 +00:20:39,670 --> 00:20:42,540 +When I go in here and +I start changing things + +505 +00:20:42,540 --> 00:20:44,650 +like let's say I change the destination. + +506 +00:20:44,650 --> 00:20:47,690 +If I change the destination SFO over here + +507 +00:20:47,690 --> 00:20:50,510 +to be somewhere else, Las Vegas or LAX + +508 +00:20:50,510 --> 00:20:51,664 +or Newark or somewhere, + +509 +00:20:51,664 --> 00:20:55,550 +it's going to cause this whole +thing over here to refetch. + +510 +00:20:55,550 --> 00:20:58,157 +My FlightAware fetch is gonna +have to get a whole new thing. + +511 +00:20:58,157 --> 00:21:01,400 +So I'm not sure that as +I'm choosing it over here + +512 +00:21:01,400 --> 00:21:04,170 +in my Picker or whatever I want behind + +513 +00:21:04,170 --> 00:21:05,930 +this thing constantly updating. + +514 +00:21:05,930 --> 00:21:09,300 +And that's what would happen +if we made FilterFlight, + +515 +00:21:09,300 --> 00:21:11,540 +this sheet, be like our PaletteEditor. + +516 +00:21:11,540 --> 00:21:14,375 +If we remember our +PaletteEditor in Emoji Art, + +517 +00:21:14,375 --> 00:21:17,170 +as we changed the name or added emoji, + +518 +00:21:17,170 --> 00:21:19,973 +it was actually changing the +palette back in our document. + +519 +00:21:19,973 --> 00:21:22,340 +That was live editing. + +520 +00:21:22,340 --> 00:21:27,340 +Our modal sheet was editing +the thing it was editing live. + +521 +00:21:27,500 --> 00:21:28,426 +So it was changing live. + +522 +00:21:28,426 --> 00:21:30,270 +I don't think we want that here. + +523 +00:21:30,270 --> 00:21:33,170 +Here I think we want a "Done" "Cancel". + +524 +00:21:33,170 --> 00:21:34,422 +We talked about this in the hints + +525 +00:21:34,422 --> 00:21:37,210 +of the homework assignment as well. + +526 +00:21:37,210 --> 00:21:39,030 +Sometimes you want live editing, + +527 +00:21:39,030 --> 00:21:40,947 +sometimes you want "Done" "Cancel". + +528 +00:21:40,947 --> 00:21:42,490 +And here I think you want "Done" "Cancel" + +529 +00:21:42,490 --> 00:21:46,280 +because you might play around +with what destination you want + +530 +00:21:46,280 --> 00:21:49,470 +then once you decide, okay, +"Done", now we'll do the fetch. + +531 +00:21:49,470 --> 00:21:52,370 +We don't wanna be wasting +money and internet resources + +532 +00:21:52,370 --> 00:21:55,480 +by fetching things that we're just picking + +533 +00:21:55,480 --> 00:21:57,840 +on the way to deciding what we want. + +534 +00:21:57,840 --> 00:21:59,730 +So we're gonna do a "Done" "Cancel" thing. + +535 +00:21:59,730 --> 00:22:02,120 +So let's put a "Done" "Cancel" on here. + +536 +00:22:02,120 --> 00:22:03,550 +Okay, I wanna put a "Done" and a "Cancel". + +537 +00:22:03,550 --> 00:22:06,480 +Now we did the "Done" Button in Emoji Art + +538 +00:22:06,480 --> 00:22:08,448 +by creating our own little title here. + +539 +00:22:08,448 --> 00:22:11,317 +I'm gonna actually +draft off NavigationView + +540 +00:22:11,317 --> 00:22:13,640 +because we know that in NavigationView, + +541 +00:22:13,640 --> 00:22:14,473 +it puts a title up here + +542 +00:22:14,473 --> 00:22:17,471 +and it has room for two +Buttons, like "Done" "Cancel". + +543 +00:22:17,471 --> 00:22:19,350 +So I'm gonna put this whole thing + +544 +00:22:19,350 --> 00:22:21,387 +in a NavigationView so I can get those. + +545 +00:22:21,387 --> 00:22:23,810 +You're gonna see that +I need this whole thing + +546 +00:22:23,810 --> 00:22:25,790 +to be in a NavigationView anyway. + +547 +00:22:25,790 --> 00:22:30,280 +So just a little bit +foresight going on here, + +548 +00:22:30,280 --> 00:22:34,050 +but it's not a bad way +to get Buttons in a title + +549 +00:22:34,050 --> 00:22:34,980 +is to put things in a NavigationView, + +550 +00:22:34,980 --> 00:22:37,910 +even if you don't plan to navigate, + +551 +00:22:37,910 --> 00:22:39,520 +which I don't really plan to navigate, + +552 +00:22:39,520 --> 00:22:42,260 +but you're gonna see I'm gonna +end up needing to navigate + +553 +00:22:42,260 --> 00:22:43,483 +in this modal sheet. + +554 +00:22:44,450 --> 00:22:46,360 +So let's put that "Done" +"Cancel" in there. + +555 +00:22:46,360 --> 00:22:47,370 +Really easy to do. + +556 +00:22:47,370 --> 00:22:50,037 +I'm just gonna say .navigationBarItems. + +557 +00:22:51,560 --> 00:22:55,552 +I'm gonna put on the leading +side, a "Cancel" button + +558 +00:22:55,552 --> 00:22:59,110 +and on the trailing side, a "Done" button. + +559 +00:22:59,110 --> 00:23:00,940 +Let's go ahead and put +a title on here too. + +560 +00:23:00,940 --> 00:23:05,940 +navigationBarTitle and call +this the "Filter Flights" sheet. + +561 +00:23:08,590 --> 00:23:09,423 +That'd be good. + +562 +00:23:09,423 --> 00:23:10,800 +So we need "Cancel" and "Done". + +563 +00:23:10,800 --> 00:23:11,890 +Those are just vars. + +564 +00:23:11,890 --> 00:23:14,710 +So cancel is some View. + +565 +00:23:14,710 --> 00:23:17,819 +It's a Button that says "Cancel". + +566 +00:23:17,819 --> 00:23:21,292 +And when this is pressed + +567 +00:23:21,292 --> 00:23:26,292 +is going to set our isPresented to false. + +568 +00:23:26,410 --> 00:23:29,970 +This is again, we pass our +isPresented in as a Binding + +569 +00:23:29,970 --> 00:23:31,390 +so that we can dismiss ourselves + +570 +00:23:31,390 --> 00:23:33,680 +and certainly cancel wants to do that, + +571 +00:23:33,680 --> 00:23:36,180 +and done, it's very similar, right? + +572 +00:23:36,180 --> 00:23:37,013 +Here's done. + +573 +00:23:37,013 --> 00:23:38,289 +It says "Done". + +574 +00:23:38,289 --> 00:23:41,170 +And it's gonna also cancel but right here, + +575 +00:23:41,170 --> 00:23:45,430 +it's going to have to +make the actual changes + +576 +00:23:45,430 --> 00:23:48,870 +because "Done" means I'm done, go do it, + +577 +00:23:48,870 --> 00:23:50,880 +do the fetch and all that stuff. + +578 +00:23:50,880 --> 00:23:54,210 +"Cancel" means just cancel +me and don't do the changes. + +579 +00:23:54,210 --> 00:23:55,970 +So we'll have to talk about +how we're gonna do this + +580 +00:23:55,970 --> 00:23:57,370 +in a moment. + +581 +00:23:57,370 --> 00:24:00,050 +All right, so we have +this navigation bar stuff, + +582 +00:24:00,050 --> 00:24:04,234 +but we need to put it in a +NavigationView of course. + +583 +00:24:04,234 --> 00:24:05,483 +I think this will work. + +584 +00:24:07,160 --> 00:24:07,993 +There we go. + +585 +00:24:07,993 --> 00:24:08,826 +Let's run. + +586 +00:24:11,370 --> 00:24:12,540 +There we go, filter. + +587 +00:24:12,540 --> 00:24:13,570 +(cheers) + +588 +00:24:13,570 --> 00:24:14,403 +There it is. + +589 +00:24:14,403 --> 00:24:15,940 +There's our FilterFlights to SFO. + +590 +00:24:15,940 --> 00:24:17,550 +We're in and NavigationView right here, + +591 +00:24:17,550 --> 00:24:18,990 +we've got Cancel and Done. + +592 +00:24:18,990 --> 00:24:20,442 +We can cancel that's good. + +593 +00:24:20,442 --> 00:24:23,050 +We can also go back here and hit Done. + +594 +00:24:23,050 --> 00:24:23,991 +That's working as well. + +595 +00:24:23,991 --> 00:24:26,425 +But of course we're not +doing any actual editing + +596 +00:24:26,425 --> 00:24:30,570 +of our FlightSearch struct, +which is what this is all about. + +597 +00:24:30,570 --> 00:24:32,163 +We wanna edit this struct. + +598 +00:24:34,030 --> 00:24:37,003 +How are we gonna do this +"Done" "Cancel" business? + +599 +00:24:37,003 --> 00:24:40,262 +One simple way to do "Done" "Cancel" + +600 +00:24:40,262 --> 00:24:44,010 +is to have your own private State here + +601 +00:24:44,950 --> 00:24:47,940 +which is a draft of what +you're trying to build. + +602 +00:24:47,940 --> 00:24:50,439 +So we're trying to edit a FlightSearch + +603 +00:24:50,439 --> 00:24:53,120 +and we're just gonna create a draft of it. + +604 +00:24:53,120 --> 00:24:56,600 +We'll have our entire UI edit this draft + +605 +00:24:56,600 --> 00:24:57,700 +and then at the end, + +606 +00:24:57,700 --> 00:24:59,620 +when it's time to make the actual changes, + +607 +00:24:59,620 --> 00:25:04,620 +we'll say self.flightSearch = self.draft. + +608 +00:25:06,200 --> 00:25:08,970 +In other words, we'll +copy into the Binding, + +609 +00:25:08,970 --> 00:25:12,022 +the bound value, this our drafts value. + +610 +00:25:12,022 --> 00:25:14,034 +And FlightSearch is a struct. + +611 +00:25:14,034 --> 00:25:16,400 +You see right here, it's a struct. + +612 +00:25:16,400 --> 00:25:20,060 +So when we say equals it copies, right? + +613 +00:25:20,060 --> 00:25:20,893 +Structs get copied. + +614 +00:25:20,893 --> 00:25:23,360 +So it will be copying what's in this draft + +615 +00:25:23,360 --> 00:25:25,363 +back into this flightSearch here. + +616 +00:25:26,360 --> 00:25:28,100 +So that works on the way out. + +617 +00:25:28,100 --> 00:25:29,540 +What about on the way in? + +618 +00:25:29,540 --> 00:25:31,886 +'Cause we essentially +wanna say something like + +619 +00:25:31,886 --> 00:25:35,390 +set this to the flightSearch, okay? + +620 +00:25:35,390 --> 00:25:37,460 +I want my draft to start out + +621 +00:25:37,460 --> 00:25:39,570 +with whatever this value +of this Binding is. + +622 +00:25:39,570 --> 00:25:41,760 +But of course we know we can't do this + +623 +00:25:41,760 --> 00:25:44,650 +because we're in the +initialization phase right here, + +624 +00:25:44,650 --> 00:25:46,510 +and this is not initialized yet + +625 +00:25:46,510 --> 00:25:48,570 +it's being passed into us + +626 +00:25:48,570 --> 00:25:50,230 +so we can't do this right? + +627 +00:25:50,230 --> 00:25:52,460 +Can't use within property initializer. + +628 +00:25:52,460 --> 00:25:54,390 +So how do we set something like this? + +629 +00:25:54,390 --> 00:25:55,960 +We need an init. + +630 +00:25:56,980 --> 00:25:58,770 +If we're gonna have an init, + +631 +00:25:58,770 --> 00:26:00,370 +it needs to have the same arguments + +632 +00:26:00,370 --> 00:26:02,660 +that this thing has over here. + +633 +00:26:02,660 --> 00:26:05,440 +So we need the flightSearch +and isPresented + +634 +00:26:05,440 --> 00:26:06,370 +as arguments to our init. + +635 +00:26:06,370 --> 00:26:10,370 +So that interesting +'cause these are Bindings. + +636 +00:26:10,370 --> 00:26:11,506 +So how are we gonna have + +637 +00:26:11,506 --> 00:26:14,847 +a FlightSearch argument here to our init? + +638 +00:26:14,847 --> 00:26:18,270 +It needs to be a Binding, right? + +639 +00:26:18,270 --> 00:26:19,776 +Somehow it needs to be a Binding here. + +640 +00:26:19,776 --> 00:26:22,340 +We're not passing a FlightSearch in here. + +641 +00:26:22,340 --> 00:26:24,367 +We're actually passing a Binding to one. + +642 +00:26:24,367 --> 00:26:26,708 +Well, remember back from lecture nine, + +643 +00:26:26,708 --> 00:26:29,010 +we talked about what these things are. + +644 +00:26:29,010 --> 00:26:31,210 +These creates struct, okay? + +645 +00:26:31,210 --> 00:26:33,420 +These property wrappers like @Binding + +646 +00:26:33,420 --> 00:26:35,810 +and @State, they create structs. + +647 +00:26:35,810 --> 00:26:38,790 +This creates a Binding struct. + +648 +00:26:38,790 --> 00:26:42,980 +So we can access that actual struct + +649 +00:26:42,980 --> 00:26:45,330 +using the underbar version of this. + +650 +00:26:45,330 --> 00:26:47,950 +And remember, there's also +the non-underbar version. + +651 +00:26:47,950 --> 00:26:51,000 +That's the wrapped value of this struct, + +652 +00:26:51,000 --> 00:26:53,230 +and then there's the +dollar version of this. + +653 +00:26:53,230 --> 00:26:56,010 +That's the projected value of this struct. + +654 +00:26:56,010 --> 00:26:57,924 +Well, here we're in initialization. + +655 +00:26:57,924 --> 00:27:01,930 +So we really can't use the +projected and wrapped values + +656 +00:27:01,930 --> 00:27:04,940 +because this needs to +be initialized, right? + +657 +00:27:04,940 --> 00:27:07,300 +Because we're in init, these +have not been initialized. + +658 +00:27:07,300 --> 00:27:08,950 +We are initializing these. + +659 +00:27:08,950 --> 00:27:11,060 +That's what we're supposed +to be doing in init. + +660 +00:27:11,060 --> 00:27:12,291 +That's what init's all about. + +661 +00:27:12,291 --> 00:27:16,520 +So we want to actually set this struct. + +662 +00:27:16,520 --> 00:27:18,843 +We're gonna say _flightSearch + +663 +00:27:20,090 --> 00:27:22,270 +equals some struct. + +664 +00:27:22,270 --> 00:27:24,890 +So we need a Binding struct right here. + +665 +00:27:24,890 --> 00:27:28,234 +So we're gonna force a Binding +struct to be sent to us. + +666 +00:27:28,234 --> 00:27:33,210 +And Binding this struct is a +generic, it has a don't-care + +667 +00:27:33,210 --> 00:27:36,250 +which is the type of the +thing it's Binding to. + +668 +00:27:36,250 --> 00:27:38,946 +So we are Binding to a FlightSearch here. + +669 +00:27:38,946 --> 00:27:41,919 +So the argument here is +Binding to a FlightSearch + +670 +00:27:41,919 --> 00:27:43,826 +and now can I say _flightSearch, + +671 +00:27:43,826 --> 00:27:46,788 +which is the actual +struct, the Binding struct + +672 +00:27:46,788 --> 00:27:50,910 +equals that Binding struct +that's being passed to us. + +673 +00:27:50,910 --> 00:27:54,340 +So this is how you can have init + +674 +00:27:54,340 --> 00:27:57,860 +where some of the vars you +need to set are Bindings. + +675 +00:27:57,860 --> 00:28:00,000 +I just declare the type of the argument + +676 +00:28:00,000 --> 00:28:02,630 +to be a Binding to the var's type + +677 +00:28:02,630 --> 00:28:06,120 +and then use underbar to +set the actual struct here. + +678 +00:28:06,120 --> 00:28:10,200 +And we can do the same +thing with isPresented here. + +679 +00:28:10,200 --> 00:28:12,690 +That is a Binding to a Bool. + +680 +00:28:12,690 --> 00:28:16,559 +And so we can also here say _isPresented + +681 +00:28:16,559 --> 00:28:21,060 +equals isPresented, the +argument to this function. + +682 +00:28:21,060 --> 00:28:22,120 +So how about the draft? + +683 +00:28:22,120 --> 00:28:23,330 +How do we set the draft? + +684 +00:28:23,330 --> 00:28:25,159 +We kinda like to say self.draft + +685 +00:28:25,159 --> 00:28:27,441 +equals this flightSearch. + +686 +00:28:27,441 --> 00:28:29,602 +And that's what we're trying to do, + +687 +00:28:29,602 --> 00:28:31,340 +but we can't really do this. + +688 +00:28:31,340 --> 00:28:34,538 +These two vars are not of the same type. + +689 +00:28:34,538 --> 00:28:38,660 +This right here is a +Binding to a FlightSearch, + +690 +00:28:38,660 --> 00:28:39,740 +that's its type, + +691 +00:28:39,740 --> 00:28:42,780 +and this is the wrapped value of this, + +692 +00:28:42,780 --> 00:28:44,410 +which is a FlightSearch. + +693 +00:28:44,410 --> 00:28:45,243 +So that's why it's saying + +694 +00:28:45,243 --> 00:28:46,750 +you can't assign a +Binding to a FlightSearch + +695 +00:28:46,750 --> 00:28:49,690 +to a FlightSearch, right? + +696 +00:28:49,690 --> 00:28:53,604 +This FlightSearch is not +the same type as this draft + +697 +00:28:53,604 --> 00:28:57,810 +'cause we're doing the +draft wrapped value here. + +698 +00:28:57,810 --> 00:28:59,770 +So we're gonna have to +initialize this State + +699 +00:28:59,770 --> 00:29:02,110 +like we learned to do last time + +700 +00:29:02,110 --> 00:29:06,700 +by sending its _draft equal to a State + +701 +00:29:06,700 --> 00:29:09,310 +with some initial wrapped value. + +702 +00:29:09,310 --> 00:29:11,070 +And what is the wrap value? + +703 +00:29:11,070 --> 00:29:16,070 +Well, interestingly, +it's not the flightSearch + +704 +00:29:16,440 --> 00:29:19,450 +because the flightSearch +here is this Binding. + +705 +00:29:19,450 --> 00:29:23,440 +It's the flightSearch's +wrapped value, right? + +706 +00:29:23,440 --> 00:29:27,320 +A Bindings wrap value is +the thing it's bound to. + +707 +00:29:27,320 --> 00:29:29,160 +So flightSearch's wrap value + +708 +00:29:29,160 --> 00:29:32,150 +is the FlightSearch that it's bound to. + +709 +00:29:32,150 --> 00:29:35,009 +So here I'm creating this draft state + +710 +00:29:35,009 --> 00:29:37,160 +initializing its struct + +711 +00:29:37,160 --> 00:29:39,800 +by creating a struct, a State struct, + +712 +00:29:39,800 --> 00:29:41,075 +whose wrapped value is the same as + +713 +00:29:41,075 --> 00:29:43,860 +the flightSearch's wrapped value. + +714 +00:29:43,860 --> 00:29:46,500 +This is why I spent so +much time in lecture 9 + +715 +00:29:46,500 --> 00:29:48,910 +going over what these +property wrappers really are + +716 +00:29:48,910 --> 00:29:52,063 +so that you'd hopefully +understand code like this. + +717 +00:29:53,200 --> 00:29:55,749 +We've copied this draft +in from our FlightSearch. + +718 +00:29:55,749 --> 00:29:58,640 +Let's double check that we +have by going to our body. + +719 +00:29:58,640 --> 00:30:00,932 +And instead of showing our +flightSearch's destination, + +720 +00:30:00,932 --> 00:30:04,420 +let's show our draft's destination. + +721 +00:30:04,420 --> 00:30:06,909 +So if this copy has happened correctly, + +722 +00:30:06,909 --> 00:30:10,220 +then this draft will be showing properly. + +723 +00:30:10,220 --> 00:30:11,270 +So let's take a look. + +724 +00:30:12,800 --> 00:30:14,190 +All right, filtering, here it is. + +725 +00:30:14,190 --> 00:30:15,840 +Oh, filter flights to SFO. + +726 +00:30:15,840 --> 00:30:18,020 +That's our draft destination, excellent. + +727 +00:30:18,020 --> 00:30:21,412 +So it obviously copied +our flightSearch in. + +728 +00:30:21,412 --> 00:30:23,482 +So now we're actually almost done. + +729 +00:30:23,482 --> 00:30:26,080 +All we need to do going forward here + +730 +00:30:26,080 --> 00:30:29,330 +is change our UI in here +from just being a TextField, + +731 +00:30:29,330 --> 00:30:31,350 +to being a bunch of Pickers and things + +732 +00:30:31,350 --> 00:30:33,350 +that are editing this draft. + +733 +00:30:33,350 --> 00:30:35,720 +We're automatically gonna +copy that draft back out + +734 +00:30:35,720 --> 00:30:37,010 +if we click the "Done" button, + +735 +00:30:37,010 --> 00:30:38,390 +we'll do nothing if we hit "Cancel", + +736 +00:30:38,390 --> 00:30:39,841 +so the draft will be ignored, + +737 +00:30:39,841 --> 00:30:43,920 +but this makes it really easy +for us to implement in here. + +738 +00:30:43,920 --> 00:30:45,520 +So let's do our first Picker. + +739 +00:30:45,520 --> 00:30:47,740 +Let's do draft destination. + +740 +00:30:47,740 --> 00:30:51,040 +Let's add a Picker that lets +us choose a new destination + +741 +00:30:51,040 --> 00:30:52,853 +for our search. + +742 +00:30:53,850 --> 00:30:56,400 +Picker has a few constructors, + +743 +00:30:56,400 --> 00:30:58,039 +but we're almost always going to use + +744 +00:30:58,039 --> 00:31:00,510 +this second one right here + +745 +00:31:00,510 --> 00:31:03,730 +that takes a title of +either a LocalizedStringKey + +746 +00:31:03,730 --> 00:31:04,606 +or a title. + +747 +00:31:04,606 --> 00:31:07,345 +And you can use a Text. + +748 +00:31:07,345 --> 00:31:09,210 +That's what this one up here is + +749 +00:31:09,210 --> 00:31:12,120 +that lets you specify +a label for the title, + +750 +00:31:12,120 --> 00:31:13,840 +but it's very common in Picker + +751 +00:31:13,840 --> 00:31:15,550 +to have the title just be a String. + +752 +00:31:15,550 --> 00:31:16,940 +So let's go ahead and do this one. + +753 +00:31:16,940 --> 00:31:19,150 +The title of this, I'm +gonna call "Destination" + +754 +00:31:19,150 --> 00:31:21,752 +because I'm setting the +destination airport here. + +755 +00:31:21,752 --> 00:31:24,280 +The second argument here to Picker, + +756 +00:31:24,280 --> 00:31:25,500 +very important one. + +757 +00:31:25,500 --> 00:31:27,643 +This is a Binding to the thing + +758 +00:31:27,643 --> 00:31:30,290 +you want to change with the Picker. + +759 +00:31:30,290 --> 00:31:35,290 +So for us, we wanna change +our draft's destination. + +760 +00:31:35,980 --> 00:31:38,550 +That is what this Picker is trying to do, + +761 +00:31:38,550 --> 00:31:40,240 +choose a new destination + +762 +00:31:40,240 --> 00:31:42,683 +in our draft FlightSearch right here. + +763 +00:31:43,520 --> 00:31:45,890 +And then this last argument content + +764 +00:31:45,890 --> 00:31:50,890 +is the list of Views that +are gonna be in our Picker. + +765 +00:31:51,800 --> 00:31:54,183 +One thing Picker, +interesting to understand is + +766 +00:31:54,183 --> 00:31:57,180 +you are going to provide a list of Views. + +767 +00:31:57,180 --> 00:32:00,330 +That's why in Picker we're +almost always gonna do a ForEach. + +768 +00:32:00,330 --> 00:32:05,330 +That's the easiest way we know +to provide a list of Views. + +769 +00:32:06,010 --> 00:32:07,040 +This is a list of Views. + +770 +00:32:07,040 --> 00:32:11,210 +And this Picker is essentially +picking between those Views. + +771 +00:32:11,210 --> 00:32:13,430 +And we're gonna show you how it determines + +772 +00:32:13,430 --> 00:32:14,880 +when you pick one of those Views, + +773 +00:32:14,880 --> 00:32:18,750 +what to update your selection to. + +774 +00:32:18,750 --> 00:32:21,010 +So let's get the Views first. + +775 +00:32:21,010 --> 00:32:22,397 +Again, we're gonna do a ForEach. + +776 +00:32:22,397 --> 00:32:24,810 +Now I want to be able to pick an airport. + +777 +00:32:24,810 --> 00:32:27,910 +So I need all my airport codes. + +778 +00:32:27,910 --> 00:32:30,700 +So I'm gonna using allAirports.codes. + +779 +00:32:30,700 --> 00:32:32,145 +We'll see how to do that in a second, + +780 +00:32:32,145 --> 00:32:35,150 +and this is String so I'm gonna do .self. + +781 +00:32:35,150 --> 00:32:37,124 +This is a ForEach after all + +782 +00:32:37,124 --> 00:32:40,620 +and this ForEach it's +gonna say airport in. + +783 +00:32:40,620 --> 00:32:43,113 +Here let's just print out the airport. + +784 +00:32:44,355 --> 00:32:46,855 +These are the airport codes +like KSFO or whatever. + +785 +00:32:47,810 --> 00:32:50,206 +Now how do we get this allAirports thing? + +786 +00:32:50,206 --> 00:32:52,050 +We're gonna have a ViewModel, + +787 +00:32:52,050 --> 00:32:54,470 +the same ViewModel I use down here + +788 +00:32:54,470 --> 00:32:57,430 +in the FlightListEntry to get allAirports, + +789 +00:32:57,430 --> 00:32:59,087 +this little ObservedObject, + +790 +00:32:59,087 --> 00:33:02,010 +I'm gonna copy and paste +that one over to here, + +791 +00:33:02,010 --> 00:33:06,590 +and it's gonna be part of +the ViewModel for this View. + +792 +00:33:06,590 --> 00:33:09,900 +And this var provides all the codes + +793 +00:33:09,900 --> 00:33:14,227 +for all the airports that +this ViewModel has ever seen. + +794 +00:33:14,227 --> 00:33:15,743 +Now we're not quite done here. + +795 +00:33:15,743 --> 00:33:18,553 +This is making a bunch of Views + +796 +00:33:18,553 --> 00:33:19,830 +that are gonna be in the Picker. + +797 +00:33:19,830 --> 00:33:21,460 +So the Picker is gonna be able to have + +798 +00:33:21,460 --> 00:33:23,070 +a View for every code, + +799 +00:33:23,070 --> 00:33:27,470 +but how do we match this +selection up to this View? + +800 +00:33:27,470 --> 00:33:29,500 +We do that with dot tag + +801 +00:33:29,500 --> 00:33:32,150 +and I'm gonna tag this with the airport. + +802 +00:33:32,150 --> 00:33:35,610 +So whenever this View is +clicked on in this Picker, + +803 +00:33:35,610 --> 00:33:37,770 +and we'll see what a Picker +looks like in just a second, + +804 +00:33:37,770 --> 00:33:40,270 +whenever you pick this View, essentially, + +805 +00:33:40,270 --> 00:33:44,700 +it's going to take this tag +and put it in this variable. + +806 +00:33:44,700 --> 00:33:47,350 +And again it's got a +Binding to this variable, + +807 +00:33:47,350 --> 00:33:49,530 +so it just puts it right in there. + +808 +00:33:49,530 --> 00:33:51,460 +And what's really important about Pickers + +809 +00:33:51,460 --> 00:33:54,984 +is that this tag has to +have exactly the same type + +810 +00:33:54,984 --> 00:33:57,930 +as this Binding is bound to. + +811 +00:33:57,930 --> 00:34:00,170 +Otherwise this makes no sense. + +812 +00:34:00,170 --> 00:34:01,820 +So luckily this is true here, + +813 +00:34:01,820 --> 00:34:03,730 +this airport code is just a String. + +814 +00:34:03,730 --> 00:34:05,780 +Our destination over here + +815 +00:34:06,650 --> 00:34:08,820 +is an airport code String right there. + +816 +00:34:08,820 --> 00:34:11,416 +So this String is exactly the same type + +817 +00:34:11,416 --> 00:34:14,083 +as these airport codes, which are Strings. + +818 +00:34:15,100 --> 00:34:16,650 +Let's see what this looks like. + +819 +00:34:18,447 --> 00:34:19,899 +All right, here's our flights. + +820 +00:34:19,899 --> 00:34:21,380 +(cheers) + +821 +00:34:21,380 --> 00:34:25,390 +Oh, well here's a Picker folks. + +822 +00:34:25,390 --> 00:34:26,480 +Okay, it's a wheel. + +823 +00:34:26,480 --> 00:34:29,486 +You can go around, pick +a different thing LAX, + +824 +00:34:29,486 --> 00:34:31,998 +Las Vegas, right there, Newark. + +825 +00:34:31,998 --> 00:34:34,573 +But this is incredibly ugly. + +826 +00:34:34,573 --> 00:34:35,620 +All right? (chuckles) + +827 +00:34:35,620 --> 00:34:37,750 +It's first of all floating off + +828 +00:34:37,750 --> 00:34:39,640 +in the middle of space right here + +829 +00:34:39,640 --> 00:34:41,170 +and also its destination + +830 +00:34:41,170 --> 00:34:43,350 +doesn't quite fit there, this title. + +831 +00:34:43,350 --> 00:34:46,200 +So this is really, really bad. + +832 +00:34:46,200 --> 00:34:48,590 +And SwiftUI is doing the best it can + +833 +00:34:48,590 --> 00:34:52,890 +given the environment that +you're asking it to show in + +834 +00:34:52,890 --> 00:34:55,390 +and really it's our fault + +835 +00:34:55,390 --> 00:34:57,410 +because when we're doing +something like this, + +836 +00:34:57,410 --> 00:35:02,143 +we know that the environment +we really wanna be in is a Form + +837 +00:35:02,143 --> 00:35:04,370 +just like we did with our palette editor. + +838 +00:35:04,370 --> 00:35:07,100 +We put all the fields in a Form, + +839 +00:35:07,100 --> 00:35:09,080 +we wanna do the exact same thing here. + +840 +00:35:09,080 --> 00:35:09,913 +There's something very interesting + +841 +00:35:09,913 --> 00:35:14,260 +that's going to happen to +this when we put it in a Form. + +842 +00:35:14,260 --> 00:35:16,010 +Now this should be working, okay? + +843 +00:35:16,010 --> 00:35:17,950 +We are picking this here's Las Vegas. + +844 +00:35:17,950 --> 00:35:19,090 +I'm gonna hit Done. + +845 +00:35:19,090 --> 00:35:22,440 +It should re-fetch Las Vegas and it does. + +846 +00:35:22,440 --> 00:35:25,285 +So it is actually editing +it, so nothing wrong there. + +847 +00:35:25,285 --> 00:35:28,682 +It's just the look of +it is so bad right now. + +848 +00:35:28,682 --> 00:35:30,420 +So let's put that thing in a Form. + +849 +00:35:30,420 --> 00:35:33,750 +Watch what happens when +I put this into a Form. + +850 +00:35:33,750 --> 00:35:35,300 +All I'm doing no change really, + +851 +00:35:35,300 --> 00:35:39,140 +except for just putting +this Picker inside a Form + +852 +00:35:39,140 --> 00:35:39,973 +and hitting run. + +853 +00:35:45,130 --> 00:35:50,010 +Filter, oh, completely different look. + +854 +00:35:50,010 --> 00:35:52,980 +This Picker has completely adapted itself + +855 +00:35:52,980 --> 00:35:54,926 +to the fact that it's in a Form. + +856 +00:35:54,926 --> 00:35:58,950 +And this is a fundamental +aspect of SwiftUI. + +857 +00:35:58,950 --> 00:36:03,740 +It adapts its controls to the +environment that they're in. + +858 +00:36:03,740 --> 00:36:05,900 +And I mentioned this earlier with Button. + +859 +00:36:05,900 --> 00:36:09,290 +Why do we use a Button +instead of just Text + +860 +00:36:09,290 --> 00:36:11,660 +with onTapGesture on it? + +861 +00:36:11,660 --> 00:36:12,493 +Well, we use a Button + +862 +00:36:12,493 --> 00:36:15,270 +because the Button knows +whether it's on an Apple watch + +863 +00:36:15,270 --> 00:36:19,740 +or an Apple TV, but it's +not just cross platform, + +864 +00:36:19,740 --> 00:36:21,120 +it's within a platform. + +865 +00:36:21,120 --> 00:36:23,500 +If you have a Picker and it's in a Form, + +866 +00:36:23,500 --> 00:36:26,290 +it knows it can use this +really cool form right here, + +867 +00:36:26,290 --> 00:36:29,797 +where it has the title +and the value side by side + +868 +00:36:29,797 --> 00:36:31,400 +and it doesn't need the wheel, + +869 +00:36:31,400 --> 00:36:34,253 +because when I click on +this, watch what happens. + +870 +00:36:35,530 --> 00:36:39,967 +It navigates to a list of +all of the airport codes. + +871 +00:36:39,967 --> 00:36:44,967 +And I can pick it here, pick +San Diego over here, Las Vegas, + +872 +00:36:45,210 --> 00:36:48,250 +and this is a much better way of doing it. + +873 +00:36:48,250 --> 00:36:49,930 +Now, one thing about the adapting + +874 +00:36:49,930 --> 00:36:51,730 +to your environment, however though, + +875 +00:36:51,730 --> 00:36:53,650 +you have to be a little bit careful, + +876 +00:36:53,650 --> 00:36:56,890 +is that it adapts because +it knows it's in a Form. + +877 +00:36:56,890 --> 00:36:58,273 +It doesn't necessarily adapt + +878 +00:36:58,273 --> 00:37:00,780 +because it knows it's in a NavigationView, + +879 +00:37:00,780 --> 00:37:02,359 +even though this adaptation + +880 +00:37:02,359 --> 00:37:04,820 +requires a NavigationView, right? + +881 +00:37:04,820 --> 00:37:07,950 +When I click on here, I'm +navigating to this View + +882 +00:37:07,950 --> 00:37:11,770 +that it's wonderfully building for us. + +883 +00:37:11,770 --> 00:37:14,750 +And if I took this NavigationView away, + +884 +00:37:14,750 --> 00:37:19,423 +let's comment this out and +go back and see what happens. + +885 +00:37:20,270 --> 00:37:23,340 +It's still gonna adapt +to a form right here, + +886 +00:37:23,340 --> 00:37:24,710 +but I can't click on it. + +887 +00:37:24,710 --> 00:37:26,940 +I'm touching it right +here nothing is happening + +888 +00:37:26,940 --> 00:37:30,550 +because I'm not in a NavigationView +so it can't navigate. + +889 +00:37:30,550 --> 00:37:33,590 +Now, if I really didn't want +this in the NavigationView, + +890 +00:37:33,590 --> 00:37:35,140 +I do because I want "Done" and "Cancel", + +891 +00:37:35,140 --> 00:37:36,121 +but if I didn't want it, + +892 +00:37:36,121 --> 00:37:38,975 +I could make this go +back to being a wheel. + +893 +00:37:38,975 --> 00:37:42,950 +So Pickers here have a .pickerStyle, + +894 +00:37:42,950 --> 00:37:45,920 +and you can say, I want this +to be the WheelPickerStyle(), + +895 +00:37:47,000 --> 00:37:50,040 +no matter what the context is. + +896 +00:37:50,040 --> 00:37:52,420 +So now we go back, we're still in a Form, + +897 +00:37:52,420 --> 00:37:57,420 +but we've got this wheel +format or look again. + +898 +00:37:57,450 --> 00:37:58,677 +Still looks bad. + +899 +00:37:58,677 --> 00:38:00,923 +So let's go back to +using our NavigationView, + +900 +00:38:00,923 --> 00:38:03,553 +it definitely looked a lot better. + +901 +00:38:11,440 --> 00:38:16,363 +Let's try and understand what +this Picker has built here. + +902 +00:38:16,363 --> 00:38:21,363 +This obviously is a List +that is built, okay? + +903 +00:38:21,490 --> 00:38:25,960 +List, capital L, List of all +the Views in this ForEach. + +904 +00:38:25,960 --> 00:38:27,730 +You see this ForEach +that's making these Texts, + +905 +00:38:27,730 --> 00:38:30,280 +these are just the Texts in here. + +906 +00:38:30,280 --> 00:38:31,670 +That's all there are in here. + +907 +00:38:31,670 --> 00:38:32,785 +But one thing that's interesting to notice + +908 +00:38:32,785 --> 00:38:37,785 +is that back here, this is +also one of these Texts. + +909 +00:38:38,150 --> 00:38:43,150 +It's the text whose tag matches +the thing we're bound to. + +910 +00:38:43,280 --> 00:38:45,030 +So this View actually appears twice. + +911 +00:38:45,030 --> 00:38:49,240 +It appears here and it appears over here + +912 +00:38:49,240 --> 00:38:50,750 +down where? + +913 +00:38:50,750 --> 00:38:52,890 +Way down here with a +little check mark by it. + +914 +00:38:52,890 --> 00:38:55,350 +So that View is used in both places. + +915 +00:38:55,350 --> 00:38:56,950 +You have to understand that +when you're making a Picker, + +916 +00:38:56,950 --> 00:38:58,130 +that this View that you're picking, + +917 +00:38:58,130 --> 00:38:59,480 +you're actually picking the View. + +918 +00:38:59,480 --> 00:39:01,815 +Now, the View is what's appearing here + +919 +00:39:01,815 --> 00:39:05,900 +and it's being reported +back to you via this tag. + +920 +00:39:05,900 --> 00:39:09,270 +So we've got this working for destination + +921 +00:39:09,270 --> 00:39:11,090 +and let's make sure it's still working. + +922 +00:39:11,090 --> 00:39:13,290 +Change the look of this thing here, + +923 +00:39:13,290 --> 00:39:16,743 +but let's change our +destination to Boston. + +924 +00:39:18,221 --> 00:39:19,054 +(cheers) + +925 +00:39:19,054 --> 00:39:20,203 +Flight into Boston. + +926 +00:39:21,670 --> 00:39:22,938 +All right, so we've got that working. + +927 +00:39:22,938 --> 00:39:25,660 +Now, let's add another thing + +928 +00:39:25,660 --> 00:39:28,100 +besides choosing our destination in here, + +929 +00:39:28,100 --> 00:39:30,040 +let's choose our origin airport. + +930 +00:39:30,040 --> 00:39:33,180 +So we only show flights to SFO from LAX + +931 +00:39:33,180 --> 00:39:34,590 +or something like that. + +932 +00:39:34,590 --> 00:39:37,433 +We can do that with almost +exactly the same code here. + +933 +00:39:38,560 --> 00:39:40,320 +This is not our destination. + +934 +00:39:40,320 --> 00:39:43,130 +We're doing our origin right here, + +935 +00:39:43,130 --> 00:39:46,080 +and the selection is our origin. + +936 +00:39:46,080 --> 00:39:46,913 +Otherwise it's the same, + +937 +00:39:46,913 --> 00:39:49,110 +we're looking for all +airport codes, et cetera. + +938 +00:39:49,110 --> 00:39:50,460 +So let's see if this works. + +939 +00:39:52,760 --> 00:39:54,500 +Right here, they're coming to SFO, + +940 +00:39:54,500 --> 00:39:57,190 +we filter destination, + +941 +00:39:57,190 --> 00:40:00,073 +looks like it's working great, origin. + +942 +00:40:01,460 --> 00:40:02,520 +Okay, this is blank. + +943 +00:40:02,520 --> 00:40:06,430 +Maybe that's okay because +we don't have an origin yet. + +944 +00:40:06,430 --> 00:40:08,330 +We didn't choose an origin, it's nil. + +945 +00:40:08,330 --> 00:40:09,640 +All right, we'll go in here. + +946 +00:40:09,640 --> 00:40:10,473 +Here's our choices. + +947 +00:40:10,473 --> 00:40:12,000 +Let's choose Denver. + +948 +00:40:12,000 --> 00:40:14,650 +Oh no, it didn't work. + +949 +00:40:14,650 --> 00:40:17,300 +Why can't I pick an origin airport here? + +950 +00:40:17,300 --> 00:40:18,464 +It keeps being blank. + +951 +00:40:18,464 --> 00:40:19,760 +And is it actually searching? + +952 +00:40:19,760 --> 00:40:22,324 +No, it's still showing +me all airports here. + +953 +00:40:22,324 --> 00:40:24,593 +So why is this not working? + +954 +00:40:25,550 --> 00:40:26,780 +Well, this is a common thing. + +955 +00:40:26,780 --> 00:40:28,777 +When people use Pickers for the first time + +956 +00:40:28,777 --> 00:40:33,150 +they miss this tiny subtlety +here that's going on. + +957 +00:40:33,150 --> 00:40:36,983 +I told you that this var + +958 +00:40:38,160 --> 00:40:42,636 +has to be exactly the +same type as this tag. + +959 +00:40:42,636 --> 00:40:45,040 +This var, what's its type? + +960 +00:40:45,040 --> 00:40:46,403 +The drafts origin? + +961 +00:40:47,400 --> 00:40:50,850 +This Optional String. + +962 +00:40:50,850 --> 00:40:54,340 +Oh, Optional String. + +963 +00:40:54,340 --> 00:40:55,980 +And what's this type? + +964 +00:40:55,980 --> 00:40:57,280 +Oh, that's a String, + +965 +00:40:57,280 --> 00:40:59,530 +'cause this is a ForEach of Strings. + +966 +00:40:59,530 --> 00:41:02,016 +So this is a String, this +is an Optional String, + +967 +00:41:02,016 --> 00:41:03,820 +that's not gonna work. + +968 +00:41:03,820 --> 00:41:05,390 +They're not exactly the same type. + +969 +00:41:05,390 --> 00:41:08,010 +They need to be exactly the same type. + +970 +00:41:08,010 --> 00:41:11,710 +Now a tricky fix to this actually + +971 +00:41:11,710 --> 00:41:16,330 +is to make this argument to +our ForEach closure here, + +972 +00:41:16,330 --> 00:41:20,113 +be a Optional String. + +973 +00:41:21,010 --> 00:41:23,297 +So remember this is equals void. + +974 +00:41:23,297 --> 00:41:26,450 +But we're just using Swift inference + +975 +00:41:26,450 --> 00:41:28,590 +to not have to specify these things. + +976 +00:41:28,590 --> 00:41:31,560 +But here I am gonna specify +it and make it this type. + +977 +00:41:31,560 --> 00:41:34,720 +Now why doesn't this break the ForEach? + +978 +00:41:34,720 --> 00:41:38,930 +Because the ForEach just +wants you to give it a closure + +979 +00:41:38,930 --> 00:41:43,150 +that you can pass its +thing into that will work. + +980 +00:41:43,150 --> 00:41:45,700 +And of course you can pass +a String into a closure + +981 +00:41:45,700 --> 00:41:47,483 +that takes an Optional String. + +982 +00:41:48,460 --> 00:41:51,078 +Now this has changed airport inside here + +983 +00:41:51,078 --> 00:41:53,190 +to be an Optional String. + +984 +00:41:53,190 --> 00:41:55,640 +So now this tag is an Optional String + +985 +00:41:55,640 --> 00:41:57,220 +and this is an Optional String. + +986 +00:41:57,220 --> 00:41:58,480 +So that fixed our problem + +987 +00:41:58,480 --> 00:42:00,250 +where these were not the same type. + +988 +00:42:00,250 --> 00:42:02,650 +However, kind of broke +us a little bit here + +989 +00:42:02,650 --> 00:42:06,910 +because it's saying airport +here is now an Optional, + +990 +00:42:06,910 --> 00:42:09,220 +and so we have to unwrap +that Optional in here. + +991 +00:42:09,220 --> 00:42:13,650 +So I'll unwrap it with the +defaulter that says something + +992 +00:42:13,650 --> 00:42:14,700 +when airport is nil. + +993 +00:42:14,700 --> 00:42:16,730 +And what do we want +when the airport is nil? + +994 +00:42:16,730 --> 00:42:21,510 +We want it to say "Any" +airport or "Unchosen" airport + +995 +00:42:21,510 --> 00:42:22,713 +or something like that. + +996 +00:42:23,640 --> 00:42:25,363 +So let's see if this works. + +997 +00:42:28,960 --> 00:42:30,270 +To our filter here. + +998 +00:42:30,270 --> 00:42:31,790 +Well, origin, that's still blank. + +999 +00:42:31,790 --> 00:42:34,490 +So that's still not right, it's not right. + +1000 +00:42:34,490 --> 00:42:35,740 +Going here. + +1001 +00:42:35,740 --> 00:42:36,573 +Okay, this is good. + +1002 +00:42:36,573 --> 00:42:39,050 +I don't see the choice of "Any" airport, + +1003 +00:42:39,050 --> 00:42:40,889 +but let's try something like Denver. + +1004 +00:42:40,889 --> 00:42:43,500 +Oh, at least this is working now. + +1005 +00:42:43,500 --> 00:42:47,250 +When I pick something in +here, Dallas, it's working, + +1006 +00:42:47,250 --> 00:42:49,590 +but that's because we've made these match. + +1007 +00:42:49,590 --> 00:42:54,590 +But there's no way for me to +go back to origin "Any", right? + +1008 +00:42:54,600 --> 00:42:56,750 +I can't set this back to nil. + +1009 +00:42:56,750 --> 00:43:01,328 +Why can't I set this origin +anywhere here to nil? + +1010 +00:43:01,328 --> 00:43:04,860 +The answer is that this list of Views + +1011 +00:43:04,860 --> 00:43:08,200 +is made from this closure right here, + +1012 +00:43:08,200 --> 00:43:11,004 +and right now it's a ForEach +of all the airport codes. + +1013 +00:43:11,004 --> 00:43:14,420 +There's no airport code which is nil. + +1014 +00:43:14,420 --> 00:43:16,900 +So since there's no nil in there, + +1015 +00:43:16,900 --> 00:43:18,584 +there's no nil in this list. + +1016 +00:43:18,584 --> 00:43:20,955 +So if we wanna be able to choose "Any", + +1017 +00:43:20,955 --> 00:43:24,089 +we have to put nil into this list. + +1018 +00:43:24,089 --> 00:43:27,840 +But this does not have +to be just the ForEach. + +1019 +00:43:27,840 --> 00:43:31,930 +We could go here and say Text("Any"), + +1020 +00:43:31,930 --> 00:43:35,790 +it's got the tag of nil, and +we've added another View. + +1021 +00:43:35,790 --> 00:43:37,700 +So there's all these ForEach's, + +1022 +00:43:37,700 --> 00:43:39,913 +but then there's this other one +right at the beginning here. + +1023 +00:43:39,913 --> 00:43:41,726 +Now this doesn't quite work + +1024 +00:43:41,726 --> 00:43:46,726 +because Swift can't infer that +this nil means String's nil. + +1025 +00:43:47,899 --> 00:43:50,970 +That's what this generic +parameter "V" cannot be inferred. + +1026 +00:43:50,970 --> 00:43:54,750 +If we go look at tag, we can look at tag, + +1027 +00:43:54,750 --> 00:43:57,730 +let's see if we take tag +zero, can probably look. + +1028 +00:43:57,730 --> 00:44:00,047 +Yeah, here's documentation for tag + +1029 +00:44:00,047 --> 00:44:02,470 +and you can see the +tag takes a don't-care. + +1030 +00:44:02,470 --> 00:44:05,296 +Tag doesn't care what type +you give it as the tag, + +1031 +00:44:05,296 --> 00:44:06,150 +all it requires + +1032 +00:44:06,150 --> 00:44:09,840 +is that this be something +that's Hashable right here. + +1033 +00:44:09,840 --> 00:44:11,300 +But if you just say nil, + +1034 +00:44:11,300 --> 00:44:13,710 +then it just doesn't +have enough information + +1035 +00:44:13,710 --> 00:44:15,860 +to know what nil are we talking about, + +1036 +00:44:15,860 --> 00:44:17,610 +'cause it could be anything. + +1037 +00:44:17,610 --> 00:44:20,990 +So how do we specify that +we want nil of String? + +1038 +00:44:20,990 --> 00:44:24,880 +There's a cool way to do +that, String Optional. + +1039 +00:44:24,880 --> 00:44:28,900 +Remember that's an enum and +we can use the case .none. + +1040 +00:44:28,900 --> 00:44:31,017 +Right, we could also use +.some of some String, + +1041 +00:44:31,017 --> 00:44:32,650 +but we're gonna use .none. + +1042 +00:44:32,650 --> 00:44:36,400 +So this is a way to say +nil for Optional Strings. + +1043 +00:44:36,400 --> 00:44:40,200 +It's a tricky little way to do that. + +1044 +00:44:40,200 --> 00:44:42,200 +So now we've added an extra thing. + +1045 +00:44:42,200 --> 00:44:43,617 +And when we go back to our filter, + +1046 +00:44:43,617 --> 00:44:46,723 +we should see another row +that says "Any" in it. + +1047 +00:44:47,674 --> 00:44:49,677 +And it's even got the View here. + +1048 +00:44:49,677 --> 00:44:50,510 +(cheers) + +1049 +00:44:50,510 --> 00:44:51,640 +There's that any row up there. + +1050 +00:44:51,640 --> 00:44:54,980 +So we can go over here to +Boise and then come back, + +1051 +00:44:54,980 --> 00:44:56,730 +go back to any and we're at any. + +1052 +00:44:56,730 --> 00:44:59,577 +And if we say done, (cheers) +it's still showing any. + +1053 +00:44:59,577 --> 00:45:02,360 +And if we go over here and go origin, + +1054 +00:45:02,360 --> 00:45:05,750 +let's do, I dunno, Denver, maybe. + +1055 +00:45:05,750 --> 00:45:07,643 +So to see if we can find a flight. + +1056 +00:45:09,061 --> 00:45:09,894 +(cheers) + +1057 +00:45:09,894 --> 00:45:11,220 +There, it is a flight from Denver today + +1058 +00:45:11,220 --> 00:45:15,093 +arrives at 1:00 in about +half an hour, all right? + +1059 +00:45:16,090 --> 00:45:19,960 +So that's what's going on +here when you have a nil + +1060 +00:45:19,960 --> 00:45:22,850 +or an Optional value and you +wanna be able to choose nil, + +1061 +00:45:22,850 --> 00:45:25,480 +you need to add a little +extra View just for that + +1062 +00:45:25,480 --> 00:45:27,390 +because the Picker is picking Views. + +1063 +00:45:27,390 --> 00:45:30,010 +It picks one of these Views. + +1064 +00:45:30,010 --> 00:45:33,250 +So you gotta have a View +for every option you want. + +1065 +00:45:33,250 --> 00:45:35,770 +Let's now go do the same +thing with airlines. + +1066 +00:45:35,770 --> 00:45:37,359 +We can filter by airlines. + +1067 +00:45:37,359 --> 00:45:38,671 +So I'm gonna put "Airline" here. + +1068 +00:45:38,671 --> 00:45:40,160 +To make my life easier + +1069 +00:45:40,160 --> 00:45:44,360 +I'm gonna replace airport with airline + +1070 +00:45:44,360 --> 00:45:47,212 +because it's almost +exactly the same thing, + +1071 +00:45:47,212 --> 00:45:49,500 +paste, paste, paste, + +1072 +00:45:49,500 --> 00:45:52,830 +and I will need to add +another ViewModel up here, + +1073 +00:45:52,830 --> 00:45:54,373 +which is all my airlines, + +1074 +00:45:57,129 --> 00:45:57,962 +airlines, + +1075 +00:45:59,918 --> 00:46:00,751 +airlines, + +1076 +00:46:01,940 --> 00:46:03,130 +Okay, so now I have a ViewModel + +1077 +00:46:03,130 --> 00:46:04,990 +for all my airlines and my airports, + +1078 +00:46:04,990 --> 00:46:06,340 +so I can do that with my airlines. + +1079 +00:46:06,340 --> 00:46:08,340 +And this airline + +1080 +00:46:08,340 --> 00:46:11,833 +is of course airline in +our draft FlightSearch. + +1081 +00:46:15,557 --> 00:46:17,793 +Yeah, here we go filter, origin, + +1082 +00:46:18,650 --> 00:46:20,620 +yeah, we could pick origin, that's good. + +1083 +00:46:20,620 --> 00:46:23,440 +Airline, any airline or maybe United. + +1084 +00:46:23,440 --> 00:46:25,940 +So let's see United flights into SFO. + +1085 +00:46:25,940 --> 00:46:27,433 +Excellent, right there. + +1086 +00:46:29,010 --> 00:46:31,163 +And we can go back to any and hit Done, + +1087 +00:46:32,314 --> 00:46:34,633 +Get the full list of flights. + +1088 +00:46:35,660 --> 00:46:37,650 +Now, one other thing that +I'd like to make better + +1089 +00:46:37,650 --> 00:46:40,560 +is these flight codes I know them well, + +1090 +00:46:40,560 --> 00:46:43,785 +as you can tell, but a +lot of people don't know + +1091 +00:46:43,785 --> 00:46:46,158 +what are these things? + +1092 +00:46:46,158 --> 00:46:48,130 +What's K-O-R-D? + +1093 +00:46:48,130 --> 00:46:49,463 +What the heck is that? + +1094 +00:46:50,570 --> 00:46:55,480 +We want these to be nicer +names than KSFO and KORD. + +1095 +00:46:55,480 --> 00:46:57,997 +We want to be names of actual airports, + +1096 +00:46:57,997 --> 00:46:59,119 +and we can do that too. + +1097 +00:46:59,119 --> 00:47:01,626 +These ViewModels up here, + +1098 +00:47:01,626 --> 00:47:03,170 +allAirports and allAirlines + +1099 +00:47:03,170 --> 00:47:05,540 +can provide us a lot better information. + +1100 +00:47:05,540 --> 00:47:07,970 +So here, instead of just +putting the airport code, + +1101 +00:47:07,970 --> 00:47:10,510 +I'm still gonna have the +tag be the airport code, + +1102 +00:47:10,510 --> 00:47:12,650 +but instead of showing the airport code, + +1103 +00:47:12,650 --> 00:47:17,383 +I'm going to use my self.allAirports, + +1104 +00:47:19,660 --> 00:47:21,091 +this airport right here, + +1105 +00:47:21,091 --> 00:47:22,844 +and that might be nil, + +1106 +00:47:22,844 --> 00:47:25,005 +they might look it up and +not be able to find it, + +1107 +00:47:25,005 --> 00:47:27,750 +so I'm going to Optional chain here + +1108 +00:47:27,750 --> 00:47:30,730 +and use what I call its friendlyName. + +1109 +00:47:30,730 --> 00:47:31,660 +And if that's not set, + +1110 +00:47:31,660 --> 00:47:34,970 +then we'll just use the airport code. + +1111 +00:47:34,970 --> 00:47:37,430 +So this is just getting a friendly name + +1112 +00:47:37,430 --> 00:47:40,529 +from this ViewModel up here, +this allAirports ViewModel, + +1113 +00:47:40,529 --> 00:47:43,590 +a friendly name of this airport. + +1114 +00:47:43,590 --> 00:47:47,587 +And we can do the same thing +for this airport down here, + +1115 +00:47:47,587 --> 00:47:49,850 +and we can do a similar +thing for the airlines, + +1116 +00:47:49,850 --> 00:47:51,193 +the allAirlines. + +1117 +00:47:55,428 --> 00:47:58,261 +So it has a friendly name feature. + +1118 +00:48:01,480 --> 00:48:03,390 +We'll go to our filter. + +1119 +00:48:03,390 --> 00:48:06,010 +Okay, destination, not KSFO anymore. + +1120 +00:48:06,010 --> 00:48:07,687 +San Francisco, California. + +1121 +00:48:07,687 --> 00:48:08,590 +(cheers) + +1122 +00:48:08,590 --> 00:48:10,630 +These are all the friendly +names of these airports. + +1123 +00:48:10,630 --> 00:48:11,610 +How about airlines? + +1124 +00:48:11,610 --> 00:48:13,323 +Yeah, we got the friendly names. + +1125 +00:48:18,640 --> 00:48:21,933 +So let's add one more thing, +not a Picker, but a Toggle. + +1126 +00:48:24,540 --> 00:48:27,830 +Toggle takes a Binding to +something that it's gonna Toggle. + +1127 +00:48:27,830 --> 00:48:30,920 +In this case I wanted to +Toggle my draft's inTheAir + +1128 +00:48:32,275 --> 00:48:34,938 +and it also takes a label + +1129 +00:48:34,938 --> 00:48:37,830 +and that'll just be for us a simple Text + +1130 +00:48:37,830 --> 00:48:40,949 +that says "Enroute Only". + +1131 +00:48:40,949 --> 00:48:43,250 +So this Toggle is going to Toggle + +1132 +00:48:43,250 --> 00:48:45,330 +whether we're showing +flights that are in the air + +1133 +00:48:45,330 --> 00:48:47,770 +or flights that are on +the ground somewhere. + +1134 +00:48:47,770 --> 00:48:48,770 +Take a look at that. + +1135 +00:48:52,970 --> 00:48:53,910 +We got Enroute Only. + +1136 +00:48:53,910 --> 00:48:55,931 +So I'm gonna turn this +off and go back to Done. + +1137 +00:48:55,931 --> 00:48:56,764 +(cheers) + +1138 +00:48:56,764 --> 00:48:59,220 +We got a lot more flights +here, not departed yet, + +1139 +00:48:59,220 --> 00:49:00,840 +flights that are +scheduled to arrive later, + +1140 +00:49:00,840 --> 00:49:02,530 +but haven't departed. + +1141 +00:49:02,530 --> 00:49:05,810 +(mouse clicking) + +1142 +00:49:05,810 --> 00:49:07,460 +All right, so that is all I really wanted + +1143 +00:49:07,460 --> 00:49:11,190 +to cover today on Picker. + +1144 +00:49:11,190 --> 00:49:12,650 +And hopefully that sets you up + +1145 +00:49:12,650 --> 00:49:14,750 +to use Pickers in your final project. + +1146 +00:49:14,750 --> 00:49:15,712 +Most of you I'm guessing + +1147 +00:49:15,712 --> 00:49:18,479 +are going to have somewhere in +your UI in your final project + +1148 +00:49:18,479 --> 00:49:19,913 +where you're gonna wanna do a Picker + +1149 +00:49:19,913 --> 00:49:22,263 +and now you know how to do it. + +1150 +00:49:23,190 --> 00:49:26,413 +- [Narrator] For more, please +visit at us stanford.edu. diff --git a/subtitles/en/Lecture 12. Core Data b/subtitles/en/Lecture 12. Core Data new file mode 100644 index 0000000..297065e --- /dev/null +++ b/subtitles/en/Lecture 12. Core Data @@ -0,0 +1,8998 @@ +1 +00:00:00,377 --> 00:00:03,127 +(dramatic music) + +2 +00:00:04,930 --> 00:00:06,843 +- [Animaker Voice] Stanford university. + +3 +00:00:08,790 --> 00:00:09,870 +- [Lecturer] All right, here we are, + +4 +00:00:09,870 --> 00:00:14,870 +lecture 12, Stanford +CS193p Spring of 2020. + +5 +00:00:15,120 --> 00:00:18,200 +Today's topic is Core Data, + +6 +00:00:18,200 --> 00:00:22,720 +which is an object-oriented database. + +7 +00:00:22,720 --> 00:00:24,470 +And we've been doing a lot of + +8 +00:00:24,470 --> 00:00:27,070 +functional programming this quarter. + +9 +00:00:27,070 --> 00:00:28,730 +Pretty much all the stuff we've been doing + +10 +00:00:28,730 --> 00:00:30,350 +has been functional programming. + +11 +00:00:30,350 --> 00:00:32,420 +We're gonna switch over now +to doing a little bit of + +12 +00:00:32,420 --> 00:00:34,700 +object-oriented programming. + +13 +00:00:34,700 --> 00:00:37,630 +Probably won't even notice +the difference here. + +14 +00:00:37,630 --> 00:00:40,417 +Although Core Data is based +on object-oriented programming + +15 +00:00:40,417 --> 00:00:43,050 +and Swift supports both object-oriented + +16 +00:00:43,050 --> 00:00:44,800 +and functional programming equally. + +17 +00:00:45,890 --> 00:00:47,500 +And we're essentially +gonna use this Core Data + +18 +00:00:47,500 --> 00:00:50,490 +infrastructure to store +and retrieve objects + +19 +00:00:50,490 --> 00:00:53,323 +or classes in a database. + +20 +00:00:54,410 --> 00:00:57,830 +Now, there's a very mature +technology out there, + +21 +00:00:57,830 --> 00:01:02,270 +it's been around for a long +time to store large data sets, + +22 +00:01:02,270 --> 00:01:04,890 +it's called SQL. + +23 +00:01:04,890 --> 00:01:09,170 +But programming in SQL is very +different than the kind of + +24 +00:01:09,170 --> 00:01:10,560 +programming we're doing in Swift, + +25 +00:01:10,560 --> 00:01:14,570 +SQL is a language and +it has its own syntax + +26 +00:01:14,570 --> 00:01:16,340 +and it's quite quite different. + +27 +00:01:16,340 --> 00:01:19,220 +And it would be a bummer for +us if all of this learning + +28 +00:01:19,220 --> 00:01:21,230 +we've done about how to program in Swift, + +29 +00:01:21,230 --> 00:01:23,670 +couldn't be applied to storing data. + +30 +00:01:23,670 --> 00:01:26,190 +So we're gonna get the +best of both worlds here + +31 +00:01:26,190 --> 00:01:30,760 +because Core Data actually +does its storage in SQL, + +32 +00:01:30,760 --> 00:01:33,220 +but we are going to interact with our data + +33 +00:01:33,220 --> 00:01:35,260 +entirely in an object-oriented way. + +34 +00:01:35,260 --> 00:01:38,750 +We're not even gonna need to +know a single SQL statement + +35 +00:01:38,750 --> 00:01:40,710 +to make this happen. + +36 +00:01:40,710 --> 00:01:44,780 +Now, the heart of making this +work in Core Data is this map. + +37 +00:01:44,780 --> 00:01:49,050 +And it is a map between the +objects and the vars on those + +38 +00:01:49,050 --> 00:01:53,960 +objects, and the tables and +rows of a relational database. + +39 +00:01:53,960 --> 00:01:56,340 +Now, if you don't know what +relational databases are + +40 +00:01:56,340 --> 00:01:57,770 +and all that, you really +don't need to know + +41 +00:01:57,770 --> 00:02:01,210 +because you're gonna be focusing +on the objects and vars, + +42 +00:02:01,210 --> 00:02:04,894 +not on the tables and rows +in a relational database, + +43 +00:02:04,894 --> 00:02:08,120 +and Xcode has a built +in editor for this map, + +44 +00:02:08,120 --> 00:02:09,810 +which is really great. + +45 +00:02:09,810 --> 00:02:13,300 +And this editor doesn't just +let us specify the objects in + +46 +00:02:13,300 --> 00:02:16,810 +vars, it lets us graphically +create the relationships + +47 +00:02:16,810 --> 00:02:19,990 +between objects, because that's +really the important part, + +48 +00:02:19,990 --> 00:02:21,740 +not just to have objects +with vars on them, + +49 +00:02:21,740 --> 00:02:23,010 +but you have objects that have + +50 +00:02:23,010 --> 00:02:25,432 +relationships to other objects. + +51 +00:02:25,432 --> 00:02:27,490 +And we'll see that some examples of that, + +52 +00:02:27,490 --> 00:02:30,290 +in a minute and in big time, +we'll see that in the demo. + +53 +00:02:31,370 --> 00:02:33,460 +So then what, you create this map, + +54 +00:02:33,460 --> 00:02:34,450 +what can you do then? + +55 +00:02:34,450 --> 00:02:39,160 +Well, Xcode behind the scenes +is gonna generate the classes, + +56 +00:02:39,160 --> 00:02:40,920 +right, the code for the classes, + +57 +00:02:40,920 --> 00:02:42,520 +that represent those objects and vars + +58 +00:02:42,520 --> 00:02:44,960 +you created in the map. + +59 +00:02:44,960 --> 00:02:49,960 +And we get to use extensions +just like we do with any other + +60 +00:02:50,000 --> 00:02:50,870 +kind of data structure. + +61 +00:02:50,870 --> 00:02:53,500 +We get to use extensions +to add our own methods + +62 +00:02:53,500 --> 00:02:55,960 +and our own computed +vars to those classes, + +63 +00:02:55,960 --> 00:03:00,630 +because, the storage vars +are stored in the database. + +64 +00:03:00,630 --> 00:03:03,810 +Then these objects that +have been created for us + +65 +00:03:03,810 --> 00:03:07,000 +and that we've extended, +service the source of data + +66 +00:03:07,000 --> 00:03:09,090 +for the elements in our UI. + +67 +00:03:09,090 --> 00:03:11,510 +So all of our SwiftUI, +that's doing everything, + +68 +00:03:11,510 --> 00:03:13,750 +it's obviously putting data on screen, + +69 +00:03:13,750 --> 00:03:17,283 +right now we store them in +ViewModels where we have + +70 +00:03:17,283 --> 00:03:19,370 +Arrays and dictionaries +and all that stuff. + +71 +00:03:19,370 --> 00:03:22,160 +Well, now this data is +going to be coming from + +72 +00:03:22,160 --> 00:03:25,120 +this database and we're just +gonna be accessing these + +73 +00:03:25,120 --> 00:03:27,100 +objects to put it on screen. + +74 +00:03:27,100 --> 00:03:30,593 +Perfectly naturally, like +we would normally do. + +75 +00:03:32,020 --> 00:03:34,110 +So what are the features of Core Data? + +76 +00:03:34,110 --> 00:03:37,270 +Of course, it has features +for creating objects. + +77 +00:03:37,270 --> 00:03:39,550 +You have to be able to create +objects in the database, + +78 +00:03:39,550 --> 00:03:43,100 +and it very naturally +lets you change the values + +79 +00:03:43,100 --> 00:03:45,850 +of the vars on these objects, +so you just change them. + +80 +00:03:45,850 --> 00:03:47,950 +They're just vars and you +set them equal to something, + +81 +00:03:47,950 --> 00:03:50,130 +boom, you just change +data in the database. + +82 +00:03:50,130 --> 00:03:53,440 +And it even has beautiful +infrastructure for establishing + +83 +00:03:53,440 --> 00:03:55,740 +these relationships between objects. + +84 +00:03:55,740 --> 00:03:57,969 +It's just a matter of +setting a var basically + +85 +00:03:57,969 --> 00:04:02,190 +to create a relationship +between one object and other and + +86 +00:04:02,190 --> 00:04:03,990 +by relationship I mean things like + +87 +00:04:03,990 --> 00:04:06,170 +a flight has an origin airport. + +88 +00:04:06,170 --> 00:04:08,230 +So flight objects and airport objects, + +89 +00:04:08,230 --> 00:04:09,533 +they have a relationship. + +90 +00:04:10,460 --> 00:04:14,080 +And there's of course a +way to save these objects + +91 +00:04:14,080 --> 00:04:16,620 +and really important +that you can fetch the + +92 +00:04:16,620 --> 00:04:20,390 +objects from the database +based on certain criteria. + +93 +00:04:20,390 --> 00:04:22,370 +You wanna say, I want all the flights that + +94 +00:04:22,370 --> 00:04:25,720 +match this certain criteria, +arrived at this certain time + +95 +00:04:25,720 --> 00:04:27,760 +or whatever that might be. + +96 +00:04:27,760 --> 00:04:31,320 +It has a great simple API for doing + +97 +00:04:31,320 --> 00:04:32,853 +the fetching of the objects. + +98 +00:04:34,040 --> 00:04:37,510 +Now it has a whole lot of other +database features on top of + +99 +00:04:37,510 --> 00:04:40,252 +it, optimistic locking +and all this things. + +100 +00:04:40,252 --> 00:04:41,870 +We are not going to talk about this. + +101 +00:04:41,870 --> 00:04:42,990 +This is an intro course, + +102 +00:04:42,990 --> 00:04:45,510 +so we're just introducing the +concept of Core Data here, + +103 +00:04:45,510 --> 00:04:48,120 +but there is a lot of stuff in there + +104 +00:04:48,120 --> 00:04:50,223 +to take this to pretty high levels. + +105 +00:04:51,800 --> 00:04:54,830 +Now let's talk about the +integration of SwiftUI, + +106 +00:04:54,830 --> 00:04:57,600 +with this Core Data database. + +107 +00:04:57,600 --> 00:05:00,320 +The objects that we create in the database + +108 +00:05:00,320 --> 00:05:02,100 +are ObservableObjects. + +109 +00:05:02,100 --> 00:05:05,760 +They're essentially +little mini ViewModels, + +110 +00:05:05,760 --> 00:05:10,230 +and there is also a very +powerful property wrapper + +111 +00:05:10,230 --> 00:05:12,323 +in SwiftUI called @FetchRequest, + +112 +00:05:13,360 --> 00:05:16,760 +which fetches these objects for us. + +113 +00:05:16,760 --> 00:05:20,020 +So this FetchRequest is more +than just a one-time fetch. + +114 +00:05:20,020 --> 00:05:22,560 +It's kind of a standing query, + +115 +00:05:22,560 --> 00:05:26,970 +that's just constantly trying +to match whatever the criteria + +116 +00:05:26,970 --> 00:05:28,140 +you're talking about are, + +117 +00:05:28,140 --> 00:05:30,330 +and returning whatever's in the database. + +118 +00:05:30,330 --> 00:05:32,050 +So as things get added to the database, + +119 +00:05:32,050 --> 00:05:35,120 +if they match the criteria +of that FetchRequest, + +120 +00:05:35,120 --> 00:05:37,470 +then it's going to update your UI. + +121 +00:05:37,470 --> 00:05:39,660 +That way our UI is always in sync + +122 +00:05:39,660 --> 00:05:42,663 +with the database +really, really fantastic. + +123 +00:05:44,570 --> 00:05:47,870 +So how do you get Core Data +into app into your app? + +124 +00:05:47,870 --> 00:05:49,030 +How do you set it up? + +125 +00:05:49,030 --> 00:05:51,750 +Well, the real way to set this up + +126 +00:05:51,750 --> 00:05:53,560 +is when you create a new project, + +127 +00:05:53,560 --> 00:05:55,430 +there's that button that you saw + +128 +00:05:55,430 --> 00:05:57,667 +called Core Data, use Core Data. + +129 +00:05:57,667 --> 00:05:59,340 +And you're gonna click that, + +130 +00:05:59,340 --> 00:06:02,100 +and it's going to do a +little bit to set you up. + +131 +00:06:02,100 --> 00:06:04,710 +Now, if you've already got +an app and you've decided, + +132 +00:06:04,710 --> 00:06:06,600 +oh, I wanna add Core Data to it, + +133 +00:06:06,600 --> 00:06:08,620 +I recommend going back +and creating a new project + +134 +00:06:08,620 --> 00:06:10,870 +and clicking this button +and then moving all your + +135 +00:06:10,870 --> 00:06:13,390 +source code over because this +button does such a really + +136 +00:06:13,390 --> 00:06:15,750 +nice job of setting things up. + +137 +00:06:15,750 --> 00:06:18,150 +So what does this button do? + +138 +00:06:18,150 --> 00:06:20,550 +Well, it creates a blank map for you. + +139 +00:06:20,550 --> 00:06:22,670 +This map that I told you +has a built in editor, + +140 +00:06:22,670 --> 00:06:23,740 +you got a blank, one of those, + +141 +00:06:23,740 --> 00:06:26,370 +so you can start adding +your objects and your vars. + +142 +00:06:26,370 --> 00:06:29,890 +It adds a little bit of +code to your AppDelegate, + +143 +00:06:29,890 --> 00:06:31,100 +which I'll show you in the demo. + +144 +00:06:31,100 --> 00:06:32,510 +You haven't seen it yet. + +145 +00:06:32,510 --> 00:06:35,190 +It's really nothing, much +of interest in there to us, + +146 +00:06:35,190 --> 00:06:36,960 +but it does add this little bit of code + +147 +00:06:36,960 --> 00:06:40,413 +that creates the database +store, the actual SQL database, + +148 +00:06:40,413 --> 00:06:42,987 +that the stuff is gonna be stored in. + +149 +00:06:42,987 --> 00:06:45,260 +And so you don't ever need +to go look at that code, + +150 +00:06:45,260 --> 00:06:47,160 +even, it just all happens automatically. + +151 +00:06:47,160 --> 00:06:48,250 +I just wanted to let you know that + +152 +00:06:48,250 --> 00:06:50,550 +it does do something in there. + +153 +00:06:50,550 --> 00:06:53,170 +Now it does add a couple of lines of code + +154 +00:06:53,170 --> 00:06:55,920 +to your SceneDelegate, +right where you create + +155 +00:06:55,920 --> 00:06:57,983 +the content View there. + +156 +00:06:58,830 --> 00:07:02,980 +One of the lines of code goes +and reaches into that store, + +157 +00:07:02,980 --> 00:07:06,527 +the SQL store code that was +in AppDelegate and it grabs + +158 +00:07:06,527 --> 00:07:10,860 +something called an +NSManagedObjectContext. + +159 +00:07:10,860 --> 00:07:14,170 +And this context is +crucial to using Core Data. + +160 +00:07:14,170 --> 00:07:17,870 +It is the window through which we see + +161 +00:07:17,870 --> 00:07:20,600 +that all the objects in our database, + +162 +00:07:20,600 --> 00:07:22,660 +and you're gonna see that we +need to contact whenever we + +163 +00:07:22,660 --> 00:07:26,500 +create objects, we do +fetches, any of that stuff. + +164 +00:07:26,500 --> 00:07:29,470 +So this two lines have +SceneDelegate code order, + +165 +00:07:29,470 --> 00:07:31,810 +go grab that context out of the store. + +166 +00:07:31,810 --> 00:07:32,920 +And then the second one, + +167 +00:07:32,920 --> 00:07:37,920 +interestingly is to pass that +context into your SwiftUI + +168 +00:07:38,750 --> 00:07:40,487 +Views via the Environment. + +169 +00:07:40,487 --> 00:07:42,830 +And we already saw +Environment, for example, + +170 +00:07:42,830 --> 00:07:44,220 +with the edit mode. + +171 +00:07:44,220 --> 00:07:45,810 +And this is using Environment again, + +172 +00:07:45,810 --> 00:07:48,970 +so that all your SwiftUI Views +will have this context so + +173 +00:07:48,970 --> 00:07:51,480 +they can see the database and get objects + +174 +00:07:51,480 --> 00:07:53,620 +out of it and all that. + +175 +00:07:53,620 --> 00:07:56,250 +So that's added to your SceneDelegate. + +176 +00:07:56,250 --> 00:07:58,330 +And that's pretty much +all the set up you need, + +177 +00:07:58,330 --> 00:08:00,810 +because now you can create +objects, fetch them, + +178 +00:08:00,810 --> 00:08:03,330 +whatever you have the window +into the database you need, + +179 +00:08:03,330 --> 00:08:05,030 +you've created your map, + +180 +00:08:05,030 --> 00:08:07,730 +whatever the objects in vars you want, + +181 +00:08:07,730 --> 00:08:08,880 +and you're on your way. + +182 +00:08:10,000 --> 00:08:11,550 +So let's take a look at that map. + +183 +00:08:11,550 --> 00:08:14,370 +I'm gonna, since the demo is gonna create + +184 +00:08:14,370 --> 00:08:17,340 +detailed map with airports +and airlines and flights + +185 +00:08:17,340 --> 00:08:20,190 +in our on route, there's no +reason to go over it here, + +186 +00:08:20,190 --> 00:08:22,350 +but just to give you +an image in your mind, + +187 +00:08:22,350 --> 00:08:24,670 +what it looks like, you know, +here's an example on the left, + +188 +00:08:24,670 --> 00:08:28,020 +we have a, looks like that is a Flight + +189 +00:08:28,020 --> 00:08:31,740 +and it's got some attributes +like when it arrived + +190 +00:08:31,740 --> 00:08:33,170 +and or it's going to arrive, + +191 +00:08:33,170 --> 00:08:36,170 +and it's ident, and even +some relationships to other + +192 +00:08:36,170 --> 00:08:38,280 +objects like, the destination airport, + +193 +00:08:38,280 --> 00:08:39,577 +the origin airport airline. + +194 +00:08:39,577 --> 00:08:40,470 +And then on the right, + +195 +00:08:40,470 --> 00:08:43,330 +you can see this graphical map +of the relationships between + +196 +00:08:43,330 --> 00:08:45,480 +Airports, Flights, and Airlines. + +197 +00:08:45,480 --> 00:08:47,970 +For example, if you see Flight, + +198 +00:08:47,970 --> 00:08:50,760 +it's got this relationship to Airport, + +199 +00:08:50,760 --> 00:08:53,360 +which is the origin and +another relationship, + +200 +00:08:53,360 --> 00:08:56,160 +the destination, and +notice that the Airport has + +201 +00:08:56,160 --> 00:08:59,430 +relationships back along the same line, + +202 +00:08:59,430 --> 00:09:01,047 +which is the Flights from this Airport, + +203 +00:09:01,047 --> 00:09:03,290 +and the Flights to this Airport. + +204 +00:09:03,290 --> 00:09:07,830 +Now, those origin and destination +relationships in Flight, + +205 +00:09:07,830 --> 00:09:10,040 +those are just Airport objects. + +206 +00:09:10,040 --> 00:09:13,590 +That's the type of those vars, +all those little black words + +207 +00:09:13,590 --> 00:09:16,120 +you see there, code name, +short name, aircraft, + +208 +00:09:16,120 --> 00:09:19,210 +those are all just gonna be +vars inside my Flight object, + +209 +00:09:19,210 --> 00:09:21,040 +my Airline object, my Airport object, + +210 +00:09:21,040 --> 00:09:24,160 +Airport object, and destination, +origin are just vars + +211 +00:09:24,160 --> 00:09:26,610 +and their type is gonna be Airport. + +212 +00:09:26,610 --> 00:09:28,800 +Now the flightsFrom and the flightsTo, + +213 +00:09:28,800 --> 00:09:30,895 +they're a little interesting because + +214 +00:09:30,895 --> 00:09:32,430 +there's multiple Flights +to and from an Airport. + +215 +00:09:32,430 --> 00:09:35,280 +So those are actually +gonna be Sets of Flights. + +216 +00:09:35,280 --> 00:09:37,740 +That's the type of that var, it's a Set, + +217 +00:09:37,740 --> 00:09:39,498 +kind of an old Objective-C-style Set. + +218 +00:09:39,498 --> 00:09:41,610 +And we'll talk about that in the demo, + +219 +00:09:41,610 --> 00:09:43,160 +but that's what's going on there. + +220 +00:09:43,160 --> 00:09:45,520 +So all of these things that +we see on the screen are just + +221 +00:09:45,520 --> 00:09:48,950 +turning into objects, Airline, +Flight, and Airport objects, + +222 +00:09:48,950 --> 00:09:51,640 +with vars, aircraft, +arrival, departure file, + +223 +00:09:51,640 --> 00:09:54,480 +those are all just vars +on each of these things. + +224 +00:09:54,480 --> 00:09:55,850 +That's what this map is doing. + +225 +00:09:55,850 --> 00:09:58,350 +And that's really all there +is to it with the map. + +226 +00:09:59,740 --> 00:10:02,640 +So once you have this map and +now you have the window that + +227 +00:10:02,640 --> 00:10:04,640 +was passed into your Environment +that we talked about from + +228 +00:10:04,640 --> 00:10:07,150 +your SceneDelegate, what can you do? + +229 +00:10:07,150 --> 00:10:09,660 +Well, you can get that window, + +230 +00:10:09,660 --> 00:10:12,590 +that managedObjectContext +via your Environment, + +231 +00:10:12,590 --> 00:10:15,617 +it's \.managedObjectContext. + +232 +00:10:15,617 --> 00:10:17,170 +And now you have this context var, + +233 +00:10:17,170 --> 00:10:19,810 +and you can use it to do +things like create an object. + +234 +00:10:19,810 --> 00:10:21,960 +You just do that by saying Flight, + +235 +00:10:21,960 --> 00:10:24,430 +with the argument context so that knows + +236 +00:10:24,430 --> 00:10:25,660 +the window into the database + +237 +00:10:25,660 --> 00:10:27,210 +and it'll create you a Flight. + +238 +00:10:27,210 --> 00:10:30,870 +Now you have a Flight this +green flight var here, + +239 +00:10:30,870 --> 00:10:33,430 +and you can just start +setting the vars on it. + +240 +00:10:33,430 --> 00:10:36,350 +Like the aircraft, set it to "B737", + +241 +00:10:36,350 --> 00:10:38,500 +Boeing 737 aircraft. + +242 +00:10:38,500 --> 00:10:41,170 +And here's another thing +I'm creating an Airport + +243 +00:10:41,170 --> 00:10:45,150 +called KSJC, and I'm +just setting it's ICAO, + +244 +00:10:45,150 --> 00:10:49,980 +which is its unique identifier +for an airport to "KSJC". + +245 +00:10:49,980 --> 00:10:52,670 +And I can even do pretty +powerful var setting + +246 +00:10:52,670 --> 00:10:57,670 +like if I set the +Flight's .origin to ksjc, + +247 +00:10:57,680 --> 00:11:00,570 +'cause kscj is an Airport, +and the origin is a var + +248 +00:11:00,570 --> 00:11:04,060 +that's of type Airport, then +that sets that relationship. + +249 +00:11:04,060 --> 00:11:07,280 +And that will also affect +the opposite relationship of + +250 +00:11:07,280 --> 00:11:10,690 +ksjc's flightsFrom, will automatically get + +251 +00:11:10,690 --> 00:11:12,460 +flight added to it. + +252 +00:11:12,460 --> 00:11:14,330 +So you don't even have to +worry about the balancing, + +253 +00:11:14,330 --> 00:11:18,620 +the two sides, one's a Set of +Flights and one is the origin. + +254 +00:11:18,620 --> 00:11:20,200 +It automatically keeps both sides. + +255 +00:11:20,200 --> 00:11:21,900 +And if I had added it +to the Set of Flights, + +256 +00:11:21,900 --> 00:11:24,410 +then it would set it as the +origin on the other side. + +257 +00:11:24,410 --> 00:11:27,040 +So it's pretty cool system in that way. + +258 +00:11:27,040 --> 00:11:28,690 +So it's just objects and vars. + +259 +00:11:28,690 --> 00:11:30,360 +So you just that's looks all like + +260 +00:11:30,360 --> 00:11:31,660 +objects and vars to us here. + +261 +00:11:31,660 --> 00:11:34,510 +We don't know anything else +about SQL or tables and rows, + +262 +00:11:34,510 --> 00:11:35,610 +just objects and vars. + +263 +00:11:37,090 --> 00:11:41,240 +Saving it, really easy, context.save(), + +264 +00:11:41,240 --> 00:11:45,590 +this throws, however, now +why would trying to save it + +265 +00:11:45,590 --> 00:11:47,597 +throw? Well, your disc +before could be full, + +266 +00:11:47,597 --> 00:11:49,390 +for one thing, it's extremely unlikely, + +267 +00:11:49,390 --> 00:11:52,610 +but your iOS device doesn't +have unlimited storage, + +268 +00:11:52,610 --> 00:11:55,890 +but there could be possibly +other errors, but you know, + +269 +00:11:55,890 --> 00:11:59,330 +generally this is not going +to fail, but it can throw. + +270 +00:11:59,330 --> 00:12:02,383 +So that's why we have to put +the try on there when we save. + +271 +00:12:03,760 --> 00:12:05,070 +Now, what about fetching objects? + +272 +00:12:05,070 --> 00:12:06,170 +Getting them out of the database? + +273 +00:12:06,170 --> 00:12:08,660 +Well, we do that with this +very important objects + +274 +00:12:08,660 --> 00:12:11,190 +in Core Data called an NSFetchRequest. + +275 +00:12:11,190 --> 00:12:12,023 +All right. + +276 +00:12:12,023 --> 00:12:13,190 +And it has a don't care there, + +277 +00:12:13,190 --> 00:12:16,510 +which is the kind of thing +that you want to fetch. + +278 +00:12:16,510 --> 00:12:19,530 +And you create one just by +specifying the name of the thing + +279 +00:12:19,530 --> 00:12:23,520 +in your map, that is that +thing you're trying to fetch. + +280 +00:12:23,520 --> 00:12:27,260 +So Flight in this case is +what I called in my map, + +281 +00:12:27,260 --> 00:12:28,770 +the objects that are Flight. + +282 +00:12:28,770 --> 00:12:30,970 +So this is gonna create +a FetchRequest that goes + +283 +00:12:30,970 --> 00:12:32,760 +and fetches Flights. + +284 +00:12:32,760 --> 00:12:33,900 +That's what this request is. + +285 +00:12:33,900 --> 00:12:37,870 +Now how does it know which +Flight to go and get? + +286 +00:12:37,870 --> 00:12:41,040 +Well, this request has a +var in it called predicate, + +287 +00:12:41,040 --> 00:12:44,100 +and you assign it an NSPredicate. + +288 +00:12:44,100 --> 00:12:46,519 +You're definitely gonna wanna +look in the documentation + +289 +00:12:46,519 --> 00:12:50,200 +of NSPredicate and see all +the incredible wide range + +290 +00:12:50,200 --> 00:12:53,601 +of things it can do to specify +which Flights you want. + +291 +00:12:53,601 --> 00:12:56,377 +So for example, I've +created a predicate here, + +292 +00:12:56,377 --> 00:12:59,120 +predicate kinda has a +little bit of a printf + +293 +00:12:59,120 --> 00:13:00,560 +kind of feel to it. + +294 +00:13:00,560 --> 00:13:02,430 +This has been around a very long time, + +295 +00:13:02,430 --> 00:13:04,343 +well before Swift ever existed. + +296 +00:13:05,290 --> 00:13:06,740 +So it's a little printf-y. + +297 +00:13:06,740 --> 00:13:09,890 +And so my predicate here +is that I want arrival is + +298 +00:13:09,890 --> 00:13:13,810 +before something, and the +origin equals something. + +299 +00:13:13,810 --> 00:13:15,680 +And then I provide the somethings. + +300 +00:13:15,680 --> 00:13:19,017 +The first something is +the current date and time. + +301 +00:13:19,017 --> 00:13:21,290 +And the second one is ksjc. + +302 +00:13:21,290 --> 00:13:22,570 +So this predicate means, + +303 +00:13:22,570 --> 00:13:25,840 +show me all the things that +have arrived before now. + +304 +00:13:25,840 --> 00:13:29,640 +So they're already arrived, +and their origin was San Jose. + +305 +00:13:29,640 --> 00:13:31,220 +They came from San Jose. + +306 +00:13:31,220 --> 00:13:33,460 +So that's the predicate I'm doing here. + +307 +00:13:33,460 --> 00:13:35,010 +So it's a little bit, you know, + +308 +00:13:35,870 --> 00:13:39,050 +texty kind of oriented predicates there, + +309 +00:13:39,050 --> 00:13:41,500 +but you have to definitely +have to go look in the + +310 +00:13:41,500 --> 00:13:44,150 +documentation for +NSPredicate to understand + +311 +00:13:44,150 --> 00:13:46,330 +all the things that it can do. + +312 +00:13:46,330 --> 00:13:47,960 +So that's specifying which of the flights + +313 +00:13:47,960 --> 00:13:48,910 +I want in a database. + +314 +00:13:48,910 --> 00:13:51,837 +Now there's one other piece of +requests that you need here, + +315 +00:13:51,837 --> 00:13:54,070 +which is something called +the sortDescriptors. + +316 +00:13:54,070 --> 00:13:56,620 +And that's because when we +make this request into the + +317 +00:13:56,620 --> 00:13:59,320 +database, it's gonna +come back as an Array. + +318 +00:13:59,320 --> 00:14:01,240 +And that Array has to be sorted. + +319 +00:14:01,240 --> 00:14:04,280 +And we specify the +sortDescriptors so the sorting can + +320 +00:14:04,280 --> 00:14:06,550 +happen on the database side, + +321 +00:14:06,550 --> 00:14:09,320 +SQL database is super +good at sorting things. + +322 +00:14:09,320 --> 00:14:12,150 +And so we're gonna let it +do the sorting if possible. + +323 +00:14:12,150 --> 00:14:14,370 +And we do that with this +sortDescriptors var, + +324 +00:14:14,370 --> 00:14:17,459 +it's just an Array of +these NSSortDescriptors, + +325 +00:14:17,459 --> 00:14:21,240 +and a SortDescriptor +simply say, what var, ident + +326 +00:14:21,240 --> 00:14:23,850 +in this case, that's +the Flight identifier, + +327 +00:14:23,850 --> 00:14:24,950 +that you wanna sort by, + +328 +00:14:24,950 --> 00:14:27,420 +and whether you want it +ascending or descending, right, + +329 +00:14:27,420 --> 00:14:29,720 +alphabetical order A to Z or Z to A. + +330 +00:14:29,720 --> 00:14:33,100 +How do we then ask our context, + +331 +00:14:33,100 --> 00:14:36,110 +our database, go fetch +these things for us? + +332 +00:14:36,110 --> 00:14:39,870 +We do that with the fetch function. + +333 +00:14:39,870 --> 00:14:43,780 +So we say context.fetch this +request and it going to go + +334 +00:14:43,780 --> 00:14:48,130 +out to the database and go +find all the flights and match + +335 +00:14:48,130 --> 00:14:51,030 +this arrival and origin +predicate that we have, + +336 +00:14:51,030 --> 00:14:52,580 +and return them to us. + +337 +00:14:52,580 --> 00:14:56,770 +Now, this fetch also can throw, +just like save can throw, + +338 +00:14:56,770 --> 00:15:00,577 +so can fetch, and so we'd need to try it. + +339 +00:15:00,577 --> 00:15:02,770 +And a lot of times we'll do +a line of code like this, + +340 +00:15:02,770 --> 00:15:05,010 +let flights = try? + +341 +00:15:05,010 --> 00:15:07,300 +and then the context.fetch. + +342 +00:15:07,300 --> 00:15:08,470 +If we do this, + +343 +00:15:08,470 --> 00:15:11,330 +then that flights var +is either gonna be nil, + +344 +00:15:11,330 --> 00:15:16,330 +if the fetch failed, empty +Array, if it did not fail, + +345 +00:15:17,120 --> 00:15:20,010 +but no flights matched our predicate. + +346 +00:15:20,010 --> 00:15:22,640 +Otherwise it's just an +Array of flight objects, + +347 +00:15:22,640 --> 00:15:24,090 +the ones that matched. + +348 +00:15:24,090 --> 00:15:26,500 +So again, very object-oriented. + +349 +00:15:26,500 --> 00:15:28,360 +I'm just getting these Flight objects + +350 +00:15:28,360 --> 00:15:29,713 +that match my predicate. + +351 +00:15:30,620 --> 00:15:32,180 +I just threw all of this on one slide, + +352 +00:15:32,180 --> 00:15:34,807 +just so you get a feel +for all of the code. + +353 +00:15:34,807 --> 00:15:37,750 +And so you have kind of a +quick reference guide to it, + +354 +00:15:37,750 --> 00:15:40,560 +but we are of course, +going to do a big demo, + +355 +00:15:40,560 --> 00:15:42,163 +shows all this stuff happening. + +356 +00:15:43,070 --> 00:15:45,230 +Now what about the integration +with all this stuff + +357 +00:15:45,230 --> 00:15:46,320 +and SwiftUI? + +358 +00:15:46,320 --> 00:15:48,250 +Well, there's two major +points of integration + +359 +00:15:48,250 --> 00:15:49,110 +we talked about. + +360 +00:15:49,110 --> 00:15:52,260 +One is this ObservedObject. + +361 +00:15:52,260 --> 00:15:55,880 +When you have a flight, as +a var in one of your SwiftUI + +362 +00:15:55,880 --> 00:15:58,880 +Views, it's going to +be an @ObservedObject. + +363 +00:15:58,880 --> 00:16:03,019 +You can then use it to do +like Text(flight.ident) here, + +364 +00:16:03,019 --> 00:16:04,723 +and just show the ident and +apply whatever you wanna do, + +365 +00:16:04,723 --> 00:16:06,670 +it's just an object. + +366 +00:16:06,670 --> 00:16:09,880 +The ObservedObjects, by the +way, as far as I can tell, + +367 +00:16:09,880 --> 00:16:11,840 +do not seem to fire automatically + +368 +00:16:11,840 --> 00:16:13,890 +when things change in the database. + +369 +00:16:13,890 --> 00:16:15,260 +So if you want them to change, + +370 +00:16:15,260 --> 00:16:18,250 +you need to explicitly +call objectWillChange. + +371 +00:16:18,250 --> 00:16:21,900 +But these do make these Flights +and Airports and Airlines + +372 +00:16:21,900 --> 00:16:24,450 +feel like little mini ViewModels. + +373 +00:16:24,450 --> 00:16:26,030 +And that's really what they are. + +374 +00:16:26,030 --> 00:16:28,743 +They're little ViewModels, +on a little flight, + +375 +00:16:29,810 --> 00:16:32,150 +but a lot of times what we +wanna show in our UI is more + +376 +00:16:32,150 --> 00:16:34,210 +than just one Flight or one Airline. + +377 +00:16:34,210 --> 00:16:36,240 +We wanna show all the +Flights, for example, + +378 +00:16:36,240 --> 00:16:38,787 +that match a certain +FetchRequest or Predicate. + +379 +00:16:38,787 --> 00:16:42,400 +And so there's another +really important feature + +380 +00:16:42,400 --> 00:16:46,800 +in SwiftUI, called the +FetchRequest property wrapper. + +381 +00:16:46,800 --> 00:16:50,760 +Now this property wrapper, you +create it with the arguments, + +382 +00:16:50,760 --> 00:16:53,150 +either the same arguments +that go to a FetchRequest, + +383 +00:16:53,150 --> 00:16:54,250 +which is the entity, + +384 +00:16:54,250 --> 00:16:56,610 +remember that entity +name thing was Flight, + +385 +00:16:56,610 --> 00:16:58,710 +and the sortDescriptors and the Predicate. + +386 +00:16:58,710 --> 00:17:00,460 +So you can create a FetchRequest that way, + +387 +00:17:00,460 --> 00:17:02,270 +or you can actually create a FetchRequest + +388 +00:17:02,270 --> 00:17:04,570 +just by giving it a +FetchRequest you created, + +389 +00:17:04,570 --> 00:17:08,350 +either way you're specifying +what things you want to fetch. + +390 +00:17:08,350 --> 00:17:10,250 +And this is a property wrapper, right? + +391 +00:17:10,250 --> 00:17:12,585 +So it's wrapping some var. + +392 +00:17:12,585 --> 00:17:16,050 +And the type of the var +that wraps, is called a + +393 +00:17:16,050 --> 00:17:19,140 +FetchedResults, also has a don't care, + +394 +00:17:19,140 --> 00:17:21,300 +and that don't care of +course is what kind of thing + +395 +00:17:21,300 --> 00:17:22,440 +it's supposed to fetch. + +396 +00:17:22,440 --> 00:17:24,784 +So that better match +whatever your FetchRequest + +397 +00:17:24,784 --> 00:17:28,140 +says that it's trying to fetch. + +398 +00:17:28,140 --> 00:17:32,000 +Now this FetchedResults +var, it's a Collection. + +399 +00:17:32,000 --> 00:17:34,940 +So you can pass it to ForEach +as you'll see in a second. + +400 +00:17:34,940 --> 00:17:37,050 +But so it's not an Array, + +401 +00:17:37,050 --> 00:17:39,420 +but if you wanted to turn +this thing into an Array + +402 +00:17:39,420 --> 00:17:42,450 +really easy, you could pass +it to an Array as Array's + +403 +00:17:42,450 --> 00:17:44,610 +initializer 'cause an +Array knows how to take any + +404 +00:17:44,610 --> 00:17:46,870 +Collection and turn it into an Array. + +405 +00:17:46,870 --> 00:17:49,370 +You could also send it +messages like sorted, + +406 +00:17:49,370 --> 00:17:51,640 +sorted can be sent to any Collection, + +407 +00:17:51,640 --> 00:17:53,010 +and it returns an Array. + +408 +00:17:53,010 --> 00:17:57,140 +And that Collection is full of +those kinds of objects which + +409 +00:17:57,140 --> 00:18:00,450 +you're fetching, Flight +objects or Airport objects. + +410 +00:18:00,450 --> 00:18:05,100 +Now what's cool about this +var that you're creating here, + +411 +00:18:05,100 --> 00:18:08,640 +Flights or Airports is that +it's continuously trying to + +412 +00:18:08,640 --> 00:18:11,450 +fetch that FetchRequest. + +413 +00:18:11,450 --> 00:18:12,283 +All right, + +414 +00:18:12,283 --> 00:18:14,620 +this is not a one-time fetch, +where it's gonna fetch out + +415 +00:18:14,620 --> 00:18:15,600 +and give you the results. + +416 +00:18:15,600 --> 00:18:18,250 +It's continuously doing this fetch. + +417 +00:18:18,250 --> 00:18:19,680 +It's like a standing query. + +418 +00:18:19,680 --> 00:18:23,550 +And so every time a new Airport +or a new Flight is added + +419 +00:18:23,550 --> 00:18:26,420 +there, or even if an existing +Airport or Flight changes + +420 +00:18:26,420 --> 00:18:29,940 +one of its vars, so that now +it matches your predicate, + +421 +00:18:29,940 --> 00:18:32,170 +it's going to update. + +422 +00:18:32,170 --> 00:18:33,460 +And when it updates, + +423 +00:18:33,460 --> 00:18:37,710 +your SwiftUI is gonna get +invalidated and redrawn. + +424 +00:18:37,710 --> 00:18:40,620 +And so your UI is always +going to be showing + +425 +00:18:40,620 --> 00:18:42,060 +what's in the database. + +426 +00:18:42,060 --> 00:18:45,520 +You don't ever have to +tell it to go fetch. + +427 +00:18:45,520 --> 00:18:48,760 +And this is all part of the +declarative nature of SwiftUI. + +428 +00:18:48,760 --> 00:18:50,650 +You don't say to do things, + +429 +00:18:50,650 --> 00:18:52,950 +in SwiftUI you just declare +the things are a certain + +430 +00:18:52,950 --> 00:18:55,160 +way, and they always are that way. + +431 +00:18:55,160 --> 00:18:56,820 +And of course, with Core Data, + +432 +00:18:56,820 --> 00:18:58,750 +we always want them to look like whatever + +433 +00:18:58,750 --> 00:19:00,110 +is in the database. + +434 +00:19:00,110 --> 00:19:03,310 +So we tend to use @FetchRequests, + +435 +00:19:03,310 --> 00:19:07,380 +sometimes even when we're just +fetching one object, right? + +436 +00:19:07,380 --> 00:19:10,570 +We might be having the +predicate, just be like ident, + +437 +00:19:10,570 --> 00:19:12,860 +equal something for a +Flight, that's ever only + +438 +00:19:12,860 --> 00:19:14,100 +gonna match one Flight. + +439 +00:19:14,100 --> 00:19:16,150 +But the great thing is +if that Flight changes, + +440 +00:19:16,150 --> 00:19:18,230 +this is going to be updated. + +441 +00:19:18,230 --> 00:19:21,150 +That's why the fact that the +ObservedObjects up there, + +442 +00:19:21,150 --> 00:19:23,813 +we were talking about don't +seem to kind of do their + +443 +00:19:23,813 --> 00:19:26,150 +objectWillChange when something changes. + +444 +00:19:26,150 --> 00:19:27,580 +That really is not a big problem, + +445 +00:19:27,580 --> 00:19:29,970 +because we would just maybe +have a FetchRequest that + +446 +00:19:29,970 --> 00:19:31,010 +fetches that one thing. + +447 +00:19:31,010 --> 00:19:34,210 +And that will change, because +FetchRequest is always + +448 +00:19:34,210 --> 00:19:35,950 +tracking what's happening in the database. + +449 +00:19:35,950 --> 00:19:38,540 +It's really a fantastic property wrapper. + +450 +00:19:38,540 --> 00:19:42,330 +This API that you're seeing +right here is a really elegant, + +451 +00:19:42,330 --> 00:19:46,060 +simple one thing to make it +so that your UI is always + +452 +00:19:46,060 --> 00:19:47,670 +matching up against Core Data. + +453 +00:19:47,670 --> 00:19:49,170 +So that's really, really cool. + +454 +00:19:50,500 --> 00:19:53,520 +By the way I show the +FetchRequest up there. + +455 +00:19:53,520 --> 00:19:55,220 +I'm creating it. + +456 +00:19:55,220 --> 00:19:58,410 +When I declare the vars with +the FetchRequest I want, + +457 +00:19:58,410 --> 00:20:00,690 +but of course you could just +declare it and I'll show you + +458 +00:20:00,690 --> 00:20:02,810 +this in the demo and then use your init + +459 +00:20:02,810 --> 00:20:05,410 +and set the _flights, right, _flights + +460 +00:20:05,410 --> 00:20:08,410 +is the actual struct, +the FetchRequest struct + +461 +00:20:08,410 --> 00:20:10,330 +to be something you create then. + +462 +00:20:10,330 --> 00:20:13,000 +So if you're passing the +predicate in, for example, + +463 +00:20:13,000 --> 00:20:15,810 +that you wanna use, you +can pass it into your init, + +464 +00:20:15,810 --> 00:20:18,610 +and then your init can just +initialize that FetchRequest + +465 +00:20:18,610 --> 00:20:21,630 +thing, just like we've +initialized, Bindings this way, + +466 +00:20:21,630 --> 00:20:24,130 +State with its wrapped value, + +467 +00:20:24,130 --> 00:20:25,877 +you can do the same thing here. + +468 +00:20:25,877 --> 00:20:27,830 +And we'll see that in the demo. + +469 +00:20:27,830 --> 00:20:31,850 +And speaking of which, lets +dive right into the demo and + +470 +00:20:31,850 --> 00:20:34,300 +show you what it looks +like to do all this stuff. + +471 +00:20:35,480 --> 00:20:38,890 +Our goal in this demo is +to convert our Enroute, + +472 +00:20:38,890 --> 00:20:42,290 +to use our Core Data database +and store all the information + +473 +00:20:42,290 --> 00:20:45,190 +that comes down from +FlightAware into a database, + +474 +00:20:45,190 --> 00:20:48,800 +and then build our whole UI by +just looking in the database. + +475 +00:20:48,800 --> 00:20:50,930 +Right now, we actually fetch this stuff. + +476 +00:20:50,930 --> 00:20:52,630 +And as it comes back in FlightAware, + +477 +00:20:52,630 --> 00:20:54,240 +we're showing it in our UI directly, + +478 +00:20:54,240 --> 00:20:56,630 +here we're gonna fetch +it all from FlightAware, + +479 +00:20:56,630 --> 00:20:58,800 +put in a database, and then have our UI, + +480 +00:20:58,800 --> 00:21:00,810 +totally just looking at the database. + +481 +00:21:00,810 --> 00:21:04,560 +And this is a common kind of +paradigm for developing an + +482 +00:21:04,560 --> 00:21:08,010 +application that fetches data, +instead of having to try and + +483 +00:21:08,010 --> 00:21:10,730 +to keep track with it +and get it all the latest + +484 +00:21:10,730 --> 00:21:11,900 +information all the time, + +485 +00:21:11,900 --> 00:21:12,977 +you just throw it in the database. + +486 +00:21:12,977 --> 00:21:15,280 +And so you're always +looking at the database + +487 +00:21:15,280 --> 00:21:18,080 +and makes your code a lot +simpler on the UI side. + +488 +00:21:18,080 --> 00:21:19,830 +That's exactly what we're gonna do. + +489 +00:21:20,690 --> 00:21:22,850 +Now, if you wanna use +Core Data in your app, + +490 +00:21:22,850 --> 00:21:27,830 +the best way to do it, is +when you say "New Project" + +491 +00:21:27,830 --> 00:21:31,950 +over here, click this +button, use Core Data. + +492 +00:21:31,950 --> 00:21:33,450 +If you click this button, use Core Data, + +493 +00:21:33,450 --> 00:21:36,770 +you're gonna get the small +amount of very important code + +494 +00:21:36,770 --> 00:21:40,640 +that hooks you up to a database, +this additional button, + +495 +00:21:40,640 --> 00:21:43,130 +by the way you use CloudKit, +that's pretty cool. + +496 +00:21:43,130 --> 00:21:45,060 +That will make it so that +everything you put in your + +497 +00:21:45,060 --> 00:21:48,360 +database gets mirrored up to iCloud. + +498 +00:21:48,360 --> 00:21:51,670 +And that way the user will +see it in all their devices + +499 +00:21:51,670 --> 00:21:52,503 +in Core Data. + +500 +00:21:52,503 --> 00:21:53,520 +Pretty amazing. + +501 +00:21:53,520 --> 00:21:55,270 +We're not gonna do that part of it. + +502 +00:21:55,270 --> 00:21:56,710 +This demo is already long enough, + +503 +00:21:56,710 --> 00:21:58,700 +so we'll just focus on the Core Data part, + +504 +00:21:58,700 --> 00:22:00,740 +but it's really not that complicated. + +505 +00:22:00,740 --> 00:22:01,610 +If you're interested in that, + +506 +00:22:01,610 --> 00:22:03,693 +you can certainly look up how to do that. + +507 +00:22:04,620 --> 00:22:06,100 +Now, if you've already started your app, + +508 +00:22:06,100 --> 00:22:08,650 +like we have with Enroute +and you wanna add, + +509 +00:22:08,650 --> 00:22:10,510 +Core Data functionality to it, + +510 +00:22:10,510 --> 00:22:12,560 +I actually recommend doing what I did, + +511 +00:22:12,560 --> 00:22:15,800 +which went right back and +created a new project anyway, + +512 +00:22:15,800 --> 00:22:18,280 +and then just copied +and pasted all my code, + +513 +00:22:18,280 --> 00:22:21,150 +dragged my files back +into the new project, + +514 +00:22:21,150 --> 00:22:23,480 +because this little switch, +it does a really good job, + +515 +00:22:23,480 --> 00:22:24,803 +by just setting things up. + +516 +00:22:25,700 --> 00:22:26,910 +And so let's look at that setup. + +517 +00:22:26,910 --> 00:22:30,050 +Let's see what it is +this little switch did. + +518 +00:22:30,050 --> 00:22:33,660 +And really added two +important pieces of code. + +519 +00:22:33,660 --> 00:22:36,300 +One is right here in this +thing called AppDelegate, + +520 +00:22:36,300 --> 00:22:39,330 +which we haven't even +looked at AppDelegate yet, + +521 +00:22:39,330 --> 00:22:41,640 +but we're gonna look at it right now, + +522 +00:22:41,640 --> 00:22:44,080 +and here you can see it's added +this thing called Core Data + +523 +00:22:44,080 --> 00:22:47,350 +stack with this persistent +container right here. + +524 +00:22:47,350 --> 00:22:51,270 +That's the thing that holds +your Core Data database. + +525 +00:22:51,270 --> 00:22:54,260 +And so we are going to use this, + +526 +00:22:54,260 --> 00:22:56,590 +to access the database. + +527 +00:22:56,590 --> 00:22:59,810 +In our SceneDelegate +where we create our little + +528 +00:22:59,810 --> 00:23:03,082 +FlightsEnrouteView, notice +it's added a couple of lines of + +529 +00:23:03,082 --> 00:23:06,500 +code here, this context, +which looks in that persistent + +530 +00:23:06,500 --> 00:23:08,760 +container, we were just talking about it, + +531 +00:23:08,760 --> 00:23:11,390 +get something called a context. + +532 +00:23:11,390 --> 00:23:15,500 +In this context is then +passed via the Environment + +533 +00:23:15,500 --> 00:23:17,050 +to all of our Views. + +534 +00:23:17,050 --> 00:23:20,760 +Now we want to be very sure +that when we put up a new + +535 +00:23:20,760 --> 00:23:23,990 +Environment of Views, like when +we use a sheet or a popover + +536 +00:23:23,990 --> 00:23:27,550 +or something like that, that +we pass this along to it. + +537 +00:23:27,550 --> 00:23:29,720 +Now remember an Environment +when you give it to a View, + +538 +00:23:29,720 --> 00:23:32,803 +all the Views that are in it's +body, actually in it's body, + +539 +00:23:32,803 --> 00:23:34,830 +get the same Environment. + +540 +00:23:34,830 --> 00:23:36,170 +So you don't have to pass them there. + +541 +00:23:36,170 --> 00:23:37,940 +But if you do a sheet or popover now, + +542 +00:23:37,940 --> 00:23:41,400 +you're kind of going +off to a new base body. + +543 +00:23:41,400 --> 00:23:43,520 +And so you do need to pass, +and you're gonna see that, + +544 +00:23:43,520 --> 00:23:45,520 +'cause of course, we do +do a sheet in this app, + +545 +00:23:45,520 --> 00:23:47,743 +we have that filter flights. + +546 +00:23:49,020 --> 00:23:52,540 +So this context is our +window onto the database. + +547 +00:23:52,540 --> 00:23:55,830 +Where is the database herself +or what is the database? + +548 +00:23:55,830 --> 00:23:59,340 +And the database is something +we designed using this little + +549 +00:23:59,340 --> 00:24:00,470 +folder right down here, + +550 +00:24:00,470 --> 00:24:03,620 +which is also provided +by that use Core Data. + +551 +00:24:03,620 --> 00:24:04,600 +Here it is. + +552 +00:24:04,600 --> 00:24:07,080 +This is all of the objects + +553 +00:24:07,080 --> 00:24:08,810 +that we're going to +create in our database. + +554 +00:24:08,810 --> 00:24:12,810 +Now, remember this is an +object-oriented programming layer + +555 +00:24:12,810 --> 00:24:16,270 +on top of, in this case, a SQL database. + +556 +00:24:16,270 --> 00:24:17,877 +A normal relational database. + +557 +00:24:17,877 --> 00:24:19,730 +And so it's doing all the mapping for us. + +558 +00:24:19,730 --> 00:24:22,070 +We don't have no idea that +that's a SQL database and we + +559 +00:24:22,070 --> 00:24:25,060 +don't wanna know, we're just +gonna create our objects. + +560 +00:24:25,060 --> 00:24:26,920 +And that's what this tool right here, + +561 +00:24:26,920 --> 00:24:30,730 +this tool that's editing +this .xcdatamodeld file + +562 +00:24:30,730 --> 00:24:33,680 +is letting us do, define +what objects we want in the + +563 +00:24:33,680 --> 00:24:37,640 +database, what vars are on those objects. + +564 +00:24:37,640 --> 00:24:39,730 +So let's dive right in +and create our objects. + +565 +00:24:39,730 --> 00:24:41,070 +This is Enroute. + +566 +00:24:41,070 --> 00:24:42,490 +What objects do we have? + +567 +00:24:42,490 --> 00:24:44,180 +Well, we have the flights. + +568 +00:24:44,180 --> 00:24:45,360 +That's the main object, + +569 +00:24:45,360 --> 00:24:47,110 +all these flights that we're showing, + +570 +00:24:47,110 --> 00:24:50,020 +but we also have some kind +of helper objects like the + +571 +00:24:50,020 --> 00:24:52,570 +airline and airport objects. + +572 +00:24:52,570 --> 00:24:56,680 +So let's create Flight, Airline +and Airport objects here. + +573 +00:24:56,680 --> 00:25:00,417 +This entities is the list +of objects that we want. + +574 +00:25:00,417 --> 00:25:03,250 +And we add them down here +where it says, add entity. + +575 +00:25:03,250 --> 00:25:05,050 +So boom, there it is. + +576 +00:25:05,050 --> 00:25:08,550 +Let's call our first entity, Airport. + +577 +00:25:08,550 --> 00:25:10,840 +Let's add another entity, + +578 +00:25:10,840 --> 00:25:15,480 +call this one, Airline, +and our third entity, + +579 +00:25:15,480 --> 00:25:17,223 +which is a Flight. + +580 +00:25:19,090 --> 00:25:20,670 +So we've created the object right here, + +581 +00:25:20,670 --> 00:25:22,210 +but they have no vars. + +582 +00:25:22,210 --> 00:25:24,680 +This on the right, over +here is showing the vars, + +583 +00:25:24,680 --> 00:25:27,270 +especially this part of +the top of your attributes, + +584 +00:25:27,270 --> 00:25:30,610 +and none of our objects +have any vars yet of course. + +585 +00:25:30,610 --> 00:25:33,320 +Let's start with the +simplest one, Airline. + +586 +00:25:33,320 --> 00:25:35,040 +It only has three vars. + +587 +00:25:35,040 --> 00:25:39,617 +It has a code, and this +code is of type String. + +588 +00:25:41,050 --> 00:25:42,490 +So this is how we add a var, + +589 +00:25:42,490 --> 00:25:44,110 +we just press the plus, + +590 +00:25:44,110 --> 00:25:47,640 +give it the vars a name, +and then it's type. + +591 +00:25:47,640 --> 00:25:51,170 +It also has a name. + +592 +00:25:51,170 --> 00:25:55,303 +The name is also a String, and +that's the full name of the + +593 +00:25:55,303 --> 00:25:59,030 +airline like "United +Airlines Incorporated", + +594 +00:25:59,030 --> 00:26:00,310 +something like that. + +595 +00:26:00,310 --> 00:26:03,930 +But it also has a short name +in the FlightAware information + +596 +00:26:03,930 --> 00:26:08,210 +that comes back and that's +like, "United" just short, short + +597 +00:26:08,210 --> 00:26:11,687 +and sweet, not quite a nickname, +but shortened name of it. + +598 +00:26:11,687 --> 00:26:12,520 +And that's it. + +599 +00:26:12,520 --> 00:26:14,820 +That's all that comes +back from FlightAware + +600 +00:26:14,820 --> 00:26:17,800 +for Airline that we're +interested right here. + +601 +00:26:17,800 --> 00:26:18,730 +What about Airport? + +602 +00:26:18,730 --> 00:26:22,530 +So Airport had a very important +thing called the ICAO, + +603 +00:26:22,530 --> 00:26:27,530 +that is a String, that's +like KSFO or KDFW, KSJC + +604 +00:26:29,190 --> 00:26:31,700 +for San Jose, that's it's unique code. + +605 +00:26:31,700 --> 00:26:33,970 +You notice they all start +with K as airports in the + +606 +00:26:33,970 --> 00:26:36,150 +United States start with K. + +607 +00:26:36,150 --> 00:26:40,410 +So that is very important +one for us to have obviously, + +608 +00:26:40,410 --> 00:26:42,170 +but they will also get +kind of cool things, + +609 +00:26:42,170 --> 00:26:44,300 +like we get the latitude and longitude. + +610 +00:26:44,300 --> 00:26:46,170 +Those are Doubles. + +611 +00:26:46,170 --> 00:26:49,630 +Those come across from +FlightAware as numbers, + +612 +00:26:49,630 --> 00:26:51,170 +and so we're gonna store them here + +613 +00:26:51,170 --> 00:26:53,513 +in our database as Doubles. + +614 +00:26:54,410 --> 00:26:57,280 +Got some other stuff like +the location of the Airport. + +615 +00:26:57,280 --> 00:27:00,750 +So for San Jose, that's +San Jose, California + +616 +00:27:00,750 --> 00:27:02,150 +is the location of it. + +617 +00:27:02,150 --> 00:27:05,910 +And we also have the +time zone that it's in. + +618 +00:27:05,910 --> 00:27:10,010 +When we fly around up there +in the skies, all the pilots, + +619 +00:27:10,010 --> 00:27:13,930 +everything is going on in GMT, +right, Greenwich meantime. + +620 +00:27:13,930 --> 00:27:17,400 +So it's nice to know, the time +zone of the actual airport + +621 +00:27:17,400 --> 00:27:19,890 +we're going to so we can +convert to local time. + +622 +00:27:19,890 --> 00:27:22,490 +And then all the airports have a name. + +623 +00:27:22,490 --> 00:27:25,210 +Like I think San Francisco +International Airport + +624 +00:27:25,210 --> 00:27:27,083 +is its full name of SFO. + +625 +00:27:28,220 --> 00:27:29,053 +That's Airports. + +626 +00:27:29,053 --> 00:27:30,290 +What about the Flight? + +627 +00:27:30,290 --> 00:27:34,170 +Flights have something called +in FlightAware an ident. + +628 +00:27:34,170 --> 00:27:38,520 +This is like UA475 United +airlines, flight 475. + +629 +00:27:38,520 --> 00:27:40,120 +That its unique identifier. + +630 +00:27:40,120 --> 00:27:41,470 +We definitely wanna be able to uniquely + +631 +00:27:41,470 --> 00:27:43,423 +identify our flights. + +632 +00:27:44,410 --> 00:27:47,640 +Our Flights also have aircraft. + +633 +00:27:47,640 --> 00:27:52,640 +So this is like, a String +"737" or something like that. + +634 +00:27:52,990 --> 00:27:56,990 +Of course we have the arrival +time and departure times. + +635 +00:27:56,990 --> 00:28:01,923 +Those are Dates, go Date +here, arrival and departure. + +636 +00:28:03,400 --> 00:28:06,100 +And it turns out that Flights +also have another Date, + +637 +00:28:06,100 --> 00:28:09,990 +which is their filed departure, +because some flights are + +638 +00:28:09,990 --> 00:28:11,870 +still on the ground, they haven't left yet + +639 +00:28:11,870 --> 00:28:14,270 +either delay or they're +not scheduled to leave yet, + +640 +00:28:14,270 --> 00:28:17,700 +but they've filed, the pilot +has filed for a certain time + +641 +00:28:17,700 --> 00:28:19,810 +that they want you to depart. + +642 +00:28:19,810 --> 00:28:20,950 +So that's it. + +643 +00:28:20,950 --> 00:28:24,560 +These are our objects and their vars, + +644 +00:28:24,560 --> 00:28:27,200 +but there's one more piece +to our object-oriented puzzle + +645 +00:28:27,200 --> 00:28:30,880 +here, which is the +relationships between objects. + +646 +00:28:30,880 --> 00:28:35,150 +For example, a Flight has an +origin and destination Airport. + +647 +00:28:35,150 --> 00:28:36,490 +It has a relationship there, + +648 +00:28:36,490 --> 00:28:38,940 +that a Flight also has an Airline. + +649 +00:28:38,940 --> 00:28:42,070 +So we can add these relationships +in this section here, + +650 +00:28:42,070 --> 00:28:45,620 +relationship, but we usually +don't do it that way. + +651 +00:28:45,620 --> 00:28:48,530 +Instead we go over here, down +to this editor style in the + +652 +00:28:48,530 --> 00:28:51,640 +corner, and we switch from +this kind of table-oriented + +653 +00:28:51,640 --> 00:28:55,010 +one we're at, to this graphical version. + +654 +00:28:55,010 --> 00:28:57,177 +And this is giving us the same +information as we just had, + +655 +00:28:57,177 --> 00:29:01,450 +depending on a little graphical +version and these individual + +656 +00:29:01,450 --> 00:29:03,080 +vars, if we click on them, + +657 +00:29:03,080 --> 00:29:05,810 +we can see the types and +all that by going over here + +658 +00:29:05,810 --> 00:29:08,350 +and bring up this third pane inspector, + +659 +00:29:08,350 --> 00:29:10,520 +which we really have not looked at, + +660 +00:29:10,520 --> 00:29:12,710 +all quarter long because +SwiftUI doesn't really use it + +661 +00:29:12,710 --> 00:29:15,380 +that much, but really valuable here. + +662 +00:29:15,380 --> 00:29:19,230 +It's the fourth tab +over in this inspector, + +663 +00:29:19,230 --> 00:29:22,330 +and showing this location is +the var and here's this type + +664 +00:29:22,330 --> 00:29:24,640 +notice it says, "Optional" right here. + +665 +00:29:24,640 --> 00:29:29,080 +This does not mean optional +like Swift Optionals. + +666 +00:29:29,080 --> 00:29:31,300 +This means it's optional in the database. + +667 +00:29:31,300 --> 00:29:33,980 +So this unfortunate, this +has the exact thing name, + +668 +00:29:33,980 --> 00:29:36,110 +but it really has nothing to do with that. + +669 +00:29:36,110 --> 00:29:39,697 +All of these vars and +Swift, will be Optionals. + +670 +00:29:40,644 --> 00:29:44,210 +And that's really a design +decision there that's made + +671 +00:29:44,210 --> 00:29:47,310 +because your database might be +corrupted and you might think + +672 +00:29:47,310 --> 00:29:50,600 +that all of these things +have values, but they don't. + +673 +00:29:50,600 --> 00:29:54,120 +They're the object was started +to be created and it failed, + +674 +00:29:54,120 --> 00:29:56,030 +and so now these vars aren't set. + +675 +00:29:56,030 --> 00:29:58,250 +So that's why these are optional. + +676 +00:29:58,250 --> 00:30:01,290 +And I'm gonna show you a +little bit of a design strategy + +677 +00:30:01,290 --> 00:30:04,300 +or whatever in my code, to +kind of identify the ones that + +678 +00:30:04,300 --> 00:30:07,584 +really should never be optional, +and cover them a little bit + +679 +00:30:07,584 --> 00:30:10,890 +with some syntactic sugar, or +really I'm just gonna use a + +680 +00:30:10,890 --> 00:30:14,070 +computed var to make them not be optional. + +681 +00:30:14,070 --> 00:30:15,150 +You'll see how we do that. + +682 +00:30:15,150 --> 00:30:17,610 +But by default, all of these +are optional and it has nothing + +683 +00:30:17,610 --> 00:30:19,700 +to do with this switch right here. + +684 +00:30:19,700 --> 00:30:20,740 +So we can set other things, + +685 +00:30:20,740 --> 00:30:22,500 +default value and things like that. + +686 +00:30:22,500 --> 00:30:25,400 +But mostly what we're doing +here in this graphical + +687 +00:30:25,400 --> 00:30:30,310 +arrangement is to create +connections between these objects. + +688 +00:30:30,310 --> 00:30:32,440 +For example, let's talk about our Flight. + +689 +00:30:32,440 --> 00:30:36,560 +It wants its destination +airport, and its origin airport. + +690 +00:30:36,560 --> 00:30:37,393 +So how do we do that? + +691 +00:30:37,393 --> 00:30:39,050 +Well, we do that with the control key. + +692 +00:30:39,050 --> 00:30:42,010 +So I'm holding down control, +you can see the plus appears. + +693 +00:30:42,010 --> 00:30:45,030 +I'm gonna drag from my Flight, + +694 +00:30:45,030 --> 00:30:48,540 +over to my Airport here and let go. + +695 +00:30:48,540 --> 00:30:52,040 +And it creates a little +relationship here, a little line. + +696 +00:30:52,040 --> 00:30:55,340 +Now this is just gonna +be a var on each side, + +697 +00:30:55,340 --> 00:30:56,270 +on the Flight side, + +698 +00:30:56,270 --> 00:30:58,790 +it's currently calling +this var newRelationship. + +699 +00:30:58,790 --> 00:31:00,880 +I'm just double clicking +on it right there, + +700 +00:31:00,880 --> 00:31:04,340 +but I actually want this to +be my destination Airport. + +701 +00:31:04,340 --> 00:31:07,180 +I'm calling this var destination. + +702 +00:31:07,180 --> 00:31:10,640 +Now, what type is this +var going to be in my code + +703 +00:31:10,640 --> 00:31:13,810 +when Xcode creates all the +code that makes this object + +704 +00:31:13,810 --> 00:31:17,280 +stuff work, this is just +gonna be a var that is a type + +705 +00:31:17,280 --> 00:31:19,980 +Airport, because the Airport is an object, + +706 +00:31:19,980 --> 00:31:21,700 +we're doing object-oriented +programming here. + +707 +00:31:21,700 --> 00:31:24,730 +Each of these is a kind of +new object that Xcode is gonna + +708 +00:31:24,730 --> 00:31:25,770 +create the code for us. + +709 +00:31:25,770 --> 00:31:27,510 +It's really kind of cool. + +710 +00:31:27,510 --> 00:31:28,990 +Now what about on this side Airport? + +711 +00:31:28,990 --> 00:31:31,830 +Well, this relationship +here is really like + +712 +00:31:31,830 --> 00:31:34,922 +the Flights to this Airport. + +713 +00:31:34,922 --> 00:31:37,470 +And this is Flights, plural, + +714 +00:31:37,470 --> 00:31:41,400 +because if I have 20 Flights +all going to the same Airport, + +715 +00:31:41,400 --> 00:31:44,330 +well then this is kind of gotta be + +716 +00:31:44,330 --> 00:31:45,690 +multiple Flights or something. + +717 +00:31:45,690 --> 00:31:46,620 +How does that work? + +718 +00:31:46,620 --> 00:31:48,550 +Because this can't be a Flight. + +719 +00:31:48,550 --> 00:31:51,040 +This has gotta be like a bunch of Flights. + +720 +00:31:51,040 --> 00:31:54,400 +And indeed the way we do +that is we can inspect this + +721 +00:31:54,400 --> 00:31:58,080 +particular relationship and +say that instead of a "To One" + +722 +00:31:58,080 --> 00:32:01,750 +relationship, where there's +one Flight per Airport here, + +723 +00:32:01,750 --> 00:32:05,860 +it is a "To Many" relationship +and you can see that the + +724 +00:32:05,860 --> 00:32:08,150 +arrow became double arrow. + +725 +00:32:08,150 --> 00:32:11,550 +Now this is no longer just one Flight. + +726 +00:32:11,550 --> 00:32:13,730 +It is multiple Flights, which makes sense. + +727 +00:32:13,730 --> 00:32:18,393 +An Airport has multiple +Flights that are heading to it. + +728 +00:32:19,560 --> 00:32:22,080 +And what is gonna be the type of this var, + +729 +00:32:22,080 --> 00:32:23,740 +this var flightsTo? + +730 +00:32:23,740 --> 00:32:27,860 +Its type is gonna be a Set of Flights. + +731 +00:32:27,860 --> 00:32:30,870 +Unfortunately, it's not +a Swift Set of Flights. + +732 +00:32:30,870 --> 00:32:34,120 +It's the old Objective-C Set of Flights. + +733 +00:32:34,120 --> 00:32:36,520 +So you're gonna see us having +to do another little bit of + +734 +00:32:36,520 --> 00:32:41,132 +cleaning up, syntactic sugar, +computed var to make this into + +735 +00:32:41,132 --> 00:32:44,800 +be what we want, which we +really want it to be a Swift Set + +736 +00:32:44,800 --> 00:32:48,000 +of Flights, not an +Objective-C set of Flights. + +737 +00:32:48,000 --> 00:32:50,400 +And this is one of the few +places where Objective-C leaks + +738 +00:32:50,400 --> 00:32:54,550 +through in Core Data +unfortunately, but easily fixed. + +739 +00:32:54,550 --> 00:32:58,320 +Now I'm gonna do another control +drag from Flight up here, + +740 +00:32:58,320 --> 00:33:00,120 +for the origin Airport. + +741 +00:33:00,120 --> 00:33:03,870 +So that new relationship +down here is origin, origin + +742 +00:33:05,020 --> 00:33:07,810 +and up here, this is the +relationship on this side + +743 +00:33:07,810 --> 00:33:11,840 +is flightsFrom, and this flightsFrom, + +744 +00:33:11,840 --> 00:33:14,190 +is also a "To Many" relationship. + +745 +00:33:14,190 --> 00:33:17,130 +So both of these are +"To Many" relationships. + +746 +00:33:17,130 --> 00:33:18,240 +And Airline, same thing as + +747 +00:33:18,240 --> 00:33:21,150 +Flight, of course, every +Flight is operated by an + +748 +00:33:21,150 --> 00:33:23,174 +Firline, so we'll have +the relationship here, + +749 +00:33:23,174 --> 00:33:25,410 +called airline on this side. + +750 +00:33:25,410 --> 00:33:27,560 +And similar here, this is flights. + +751 +00:33:27,560 --> 00:33:32,020 +These are all of the Flights +being operated by this Airline. + +752 +00:33:32,020 --> 00:33:34,423 +So that is a "To Many" relationship. + +753 +00:33:35,450 --> 00:33:38,190 +Now all of this work we're +doing here to connect these up + +754 +00:33:38,190 --> 00:33:40,750 +and create these little relationship vars, + +755 +00:33:40,750 --> 00:33:43,830 +we can see it back in the +normal editor style right here. + +756 +00:33:43,830 --> 00:33:44,900 +So here's Airline. + +757 +00:33:44,900 --> 00:33:48,550 +It has flights, Airport +has flightsFrom and to, + +758 +00:33:48,550 --> 00:33:51,743 +Flight has destination, +origin, and airline. + +759 +00:33:53,120 --> 00:33:54,120 +So that's it. + +760 +00:33:54,120 --> 00:33:58,920 +That is how we build +our object model here. + +761 +00:33:58,920 --> 00:34:02,870 +All the code that's required +to make these objects exist and + +762 +00:34:02,870 --> 00:34:07,507 +have all these vars exist, is +totally done for us by Xcode. + +763 +00:34:07,507 --> 00:34:09,330 +And we just hit build here. + +764 +00:34:09,330 --> 00:34:11,820 +It goes through and creates all the code + +765 +00:34:11,820 --> 00:34:13,950 +that's necessary to make that work. + +766 +00:34:13,950 --> 00:34:17,190 +The only code we're going +to add is in extensions. + +767 +00:34:17,190 --> 00:34:20,490 +So we're gonna add some +code in extensions here. + +768 +00:34:20,490 --> 00:34:21,970 +This is object-oriented programming, + +769 +00:34:21,970 --> 00:34:24,830 +of course we want our objects +to do more than just have + +770 +00:34:24,830 --> 00:34:28,430 +these vars, we want it to +have some behavior as well. + +771 +00:34:28,430 --> 00:34:31,313 +We'll be adding that +behavior using extensions. + +772 +00:34:32,310 --> 00:34:33,510 +Let's go back now. + +773 +00:34:33,510 --> 00:34:35,620 +Now that we have our +whole object model here, + +774 +00:34:35,620 --> 00:34:37,510 +we have all the objects we wanna create, + +775 +00:34:37,510 --> 00:34:40,260 +lets go use them in our UI. + +776 +00:34:40,260 --> 00:34:43,500 +So here's our UI code that +we've built from last time, + +777 +00:34:43,500 --> 00:34:46,860 +it's still based on this +FlightFetcher mechanism, + +778 +00:34:46,860 --> 00:34:49,270 +and we're gonna completely +replace the FlightFetcher. + +779 +00:34:49,270 --> 00:34:52,560 +I'm gonna eventually comment +FlightFetcher out completely. + +780 +00:34:52,560 --> 00:34:55,790 +And instead we're gonna use +an object-oriented approach + +781 +00:34:55,790 --> 00:34:56,853 +to building our UI. + +782 +00:34:58,060 --> 00:35:00,580 +By the way, before we get started, + +783 +00:35:00,580 --> 00:35:02,070 +take a look at the top of this file, + +784 +00:35:02,070 --> 00:35:04,100 +you see import Core Data. + +785 +00:35:04,100 --> 00:35:06,490 +You wanna make sure you're +importing Core Data in any + +786 +00:35:06,490 --> 00:35:08,990 +files that you're gonna be +doing this Core Data stuff in, + +787 +00:35:08,990 --> 00:35:11,200 +otherwise symbols like +NSManagedObjectContext are + +788 +00:35:12,690 --> 00:35:15,153 +not going to be defined. + +789 +00:35:16,050 --> 00:35:18,900 +Now I'm gonna start with +this very important struct + +790 +00:35:18,900 --> 00:35:20,270 +right here, FlightSearch, + +791 +00:35:20,270 --> 00:35:24,260 +which currently is looking +up airports by their codes + +792 +00:35:24,260 --> 00:35:26,530 +and airlines by their codes. + +793 +00:35:26,530 --> 00:35:28,750 +And I'm gonna switch this +to be object-oriented. + +794 +00:35:28,750 --> 00:35:31,740 +My destination is not gonna +be a String like "KPAO", + +795 +00:35:31,740 --> 00:35:34,120 +it's going to be an Airport. + +796 +00:35:34,120 --> 00:35:34,980 +And same thing here. + +797 +00:35:34,980 --> 00:35:38,210 +My origin is going to +be an Optional Airport, + +798 +00:35:38,210 --> 00:35:41,500 +and my airline is going to be an Airline. + +799 +00:35:41,500 --> 00:35:46,100 +So this is going to totally +transform all of our code + +800 +00:35:46,100 --> 00:35:48,193 +to be object-oriented. + +801 +00:35:49,190 --> 00:35:54,190 +By the way, sometimes when +you build your object model, + +802 +00:35:54,515 --> 00:35:57,860 +the rest of your code, won't +get the message about it. + +803 +00:35:57,860 --> 00:36:00,510 +Like we still have +undeclared Airport again, + +804 +00:36:00,510 --> 00:36:03,510 +as Xcode can be building that +for us behind the scenes. + +805 +00:36:03,510 --> 00:36:05,160 +I usually will just try and build here, + +806 +00:36:05,160 --> 00:36:06,913 +sometimes that'll fix it. + +807 +00:36:08,480 --> 00:36:09,313 +Yeah that didn't quite get it. + +808 +00:36:09,313 --> 00:36:13,060 +Another one to do is go +back to your Model over here + +809 +00:36:13,060 --> 00:36:16,800 +and just do a build, +sometimes that'll get it going + +810 +00:36:16,800 --> 00:36:18,350 +see if that fixed it over here. + +811 +00:36:20,199 --> 00:36:22,080 +And it looked like it did. + +812 +00:36:22,080 --> 00:36:23,740 +So lemme see what kind of errors we got. + +813 +00:36:23,740 --> 00:36:25,660 +So we still have bunch of errors obviously + +814 +00:36:25,660 --> 00:36:29,180 +we have our whole code is based +on this thing being Strings. + +815 +00:36:29,180 --> 00:36:31,040 +And these are no longer Strings. + +816 +00:36:31,040 --> 00:36:34,270 +So let's just work our way +through the problems that we + +817 +00:36:34,270 --> 00:36:36,880 +introduced by changing +this to be object-oriented, + +818 +00:36:36,880 --> 00:36:37,940 +and fix them one by one. + +819 +00:36:37,940 --> 00:36:40,330 +And along the way, we're +gonna learn a lot about how to + +820 +00:36:40,330 --> 00:36:42,390 +create these objects in the database, + +821 +00:36:42,390 --> 00:36:45,860 +how to go look them up and +find them in the database. + +822 +00:36:45,860 --> 00:36:49,030 +That's all gonna be part and +parcel of using Core Data + +823 +00:36:49,030 --> 00:36:51,420 +to make this stuff object-oriented. + +824 +00:36:51,420 --> 00:36:52,640 +So let's start with the very first one. + +825 +00:36:52,640 --> 00:36:55,701 +It says here, cannot convert +value type String to expected + +826 +00:36:55,701 --> 00:36:57,840 +type argument Airport. + +827 +00:36:57,840 --> 00:37:01,320 +Okay, we already see one case +here where it's using a String + +828 +00:37:01,320 --> 00:37:03,060 +for an airport instead +of the Airport object. + +829 +00:37:03,060 --> 00:37:06,363 +So let's click on this, takes +us to our SceneDelegate, + +830 +00:37:07,380 --> 00:37:09,670 +and sure enough, right here, +we're trying to create a + +831 +00:37:09,670 --> 00:37:13,600 +FlightSearch with a String, +which again, destination applied + +832 +00:37:13,600 --> 00:37:16,560 +search used to be a String, +we just changed it to Airport. + +833 +00:37:16,560 --> 00:37:18,870 +So let's create a little local variable + +834 +00:37:18,870 --> 00:37:20,003 +to be our Airport here. + +835 +00:37:20,003 --> 00:37:24,000 +And I'm gonna say, let +airport equal something. + +836 +00:37:24,000 --> 00:37:28,270 +And this airport has to be +some sort of Airport object. + +837 +00:37:28,270 --> 00:37:33,210 +Now it is possible to create +an object directly using this + +838 +00:37:33,210 --> 00:37:35,300 +thing called the context, right? + +839 +00:37:35,300 --> 00:37:39,590 +The context we talked about is +this window into the database + +840 +00:37:39,590 --> 00:37:42,350 +that we get from that little use Core Data + +841 +00:37:42,350 --> 00:37:43,183 +button right here. + +842 +00:37:43,183 --> 00:37:44,840 +And this context is super important. + +843 +00:37:44,840 --> 00:37:48,170 +Everything we do is going +through that window of it, + +844 +00:37:48,170 --> 00:37:49,030 +to the database. + +845 +00:37:49,030 --> 00:37:51,750 +That's how we do +everything in the database, + +846 +00:37:51,750 --> 00:37:55,690 +but we're not gonna do that +here because it might well be + +847 +00:37:55,690 --> 00:37:57,860 +that this Airport that +I'm trying to create here, + +848 +00:37:57,860 --> 00:37:59,870 +which I'm essentially +trying to create the Airport + +849 +00:37:59,870 --> 00:38:04,870 +KSFO right, this Airport might +already be in the database. + +850 +00:38:05,600 --> 00:38:07,570 +So I kind of need a little function here, + +851 +00:38:07,570 --> 00:38:12,480 +which I'm gonna call withICAO, +which takes this String + +852 +00:38:12,480 --> 00:38:15,910 +and looks it up in the database, +and if it finds an Airport + +853 +00:38:15,910 --> 00:38:17,950 +object, it gives it to me. + +854 +00:38:17,950 --> 00:38:20,350 +And if it doesn't, it makes one, + +855 +00:38:20,350 --> 00:38:22,050 +and not only makes one, +but goes and fetches it + +856 +00:38:22,050 --> 00:38:23,830 +from FlightAware too. + +857 +00:38:23,830 --> 00:38:25,640 +So that's what this little +function is gonna do. + +858 +00:38:25,640 --> 00:38:28,970 +Now, how do we add a function +to our Airport object + +859 +00:38:28,970 --> 00:38:30,470 +that Xcode created for us? + +860 +00:38:30,470 --> 00:38:33,040 +We're gonna do it with an extension. + +861 +00:38:33,040 --> 00:38:35,450 +And we're just gonna extend this class, + +862 +00:38:35,450 --> 00:38:38,160 +this object-oriented class +Airport, to have this static + +863 +00:38:38,160 --> 00:38:41,590 +function, which lets us +look an airport up by name. + +864 +00:38:41,590 --> 00:38:42,990 +So let's go do that. + +865 +00:38:42,990 --> 00:38:45,520 +I actually created that file here, + +866 +00:38:45,520 --> 00:38:48,390 +Airport and blank file for now. + +867 +00:38:48,390 --> 00:38:52,319 +And I'm gonna say extension of Airport, + +868 +00:38:52,319 --> 00:38:55,730 +and here I'm gonna do this +static ofunc withICAO. + +869 +00:38:57,021 --> 00:38:59,060 +And it's gonna take that +little special code that I was + +870 +00:38:59,060 --> 00:39:02,960 +telling you about, and it's +gonna return an Airport. + +871 +00:39:02,960 --> 00:39:07,960 +And this is going to just look +up that ICAO in Core Data. + +872 +00:39:08,630 --> 00:39:11,893 +And if it finds it, return it, + +873 +00:39:12,920 --> 00:39:17,050 +if not, then we're going to create one + +874 +00:39:17,050 --> 00:39:20,330 +and fetch from FlightAware. + +875 +00:39:20,330 --> 00:39:23,680 +So that's what this +function is going to do. + +876 +00:39:23,680 --> 00:39:26,420 +So let's start with this, look up, + +877 +00:39:26,420 --> 00:39:27,440 +still complaining about that, + +878 +00:39:27,440 --> 00:39:29,430 +we won't worry about that for now. + +879 +00:39:29,430 --> 00:39:33,090 +We want to look up this code in Core Data. + +880 +00:39:33,090 --> 00:39:35,430 +So how do we look things up in Core Data + +881 +00:39:35,430 --> 00:39:37,510 +to see if there's something there? + +882 +00:39:37,510 --> 00:39:39,630 +We did this with a very +important object called + +883 +00:39:39,630 --> 00:39:41,333 +a FetchRequest, NSFetchRequest. + +884 +00:39:42,580 --> 00:39:47,120 +In fact, so I'm gonna let +request equal an NSFetchRequest + +885 +00:39:47,120 --> 00:39:50,680 +now, NSFetchRequest is +generic, it has a don't care, + +886 +00:39:50,680 --> 00:39:54,523 +which is the kind of object +you're trying to fetch. + +887 +00:39:55,940 --> 00:40:00,210 +Then you specify the +entity name as a String. + +888 +00:40:00,210 --> 00:40:03,787 +And this String is just whatever you put + +889 +00:40:03,787 --> 00:40:07,260 +here as the name of your entity. + +890 +00:40:07,260 --> 00:40:09,213 +So "Airline", "Airport" or "Flight". + +891 +00:40:10,460 --> 00:40:12,520 +So this is how you create a FetchRequest. + +892 +00:40:12,520 --> 00:40:16,130 +Now a FetchRequest is +essentially a guide that + +893 +00:40:16,130 --> 00:40:19,210 +we're going to use to have the database, + +894 +00:40:19,210 --> 00:40:22,730 +know which Airport we want +or which Airports, might be + +895 +00:40:22,730 --> 00:40:24,240 +looking for multiple Airports. + +896 +00:40:24,240 --> 00:40:26,240 +We might be looking for +Airports by time zone, + +897 +00:40:26,240 --> 00:40:27,877 +so we can get multiple Airports here, + +898 +00:40:27,877 --> 00:40:30,230 +and this request is gonna let us specify + +899 +00:40:30,230 --> 00:40:32,570 +which ones we want. + +900 +00:40:32,570 --> 00:40:36,220 +So the request has two +really important parts to it. + +901 +00:40:36,220 --> 00:40:39,490 +One is called its predicate, + +902 +00:40:39,490 --> 00:40:42,500 +and its predicate is the, +which ones do you want? + +903 +00:40:42,500 --> 00:40:46,000 +And you create that with an +object called an NSPredicate. + +904 +00:40:46,000 --> 00:40:50,160 +And it kinda has a printf +sort of feel to it, + +905 +00:40:50,160 --> 00:40:52,860 +where you give it a format +for what you wanna search + +906 +00:40:52,860 --> 00:40:54,720 +and then any arguments that fit in there. + +907 +00:40:54,720 --> 00:40:56,770 +So it's again pre-Swift. + +908 +00:40:56,770 --> 00:41:01,040 +So it doesn't feel super +Swift-y because it's printf-y, + +909 +00:41:01,040 --> 00:41:03,550 +but you'll get used to it really easily. + +910 +00:41:03,550 --> 00:41:04,610 +And for example, in our case, + +911 +00:41:04,610 --> 00:41:09,250 +we want the ICAO to equal something. + +912 +00:41:09,250 --> 00:41:10,930 +And what is that something? + +913 +00:41:10,930 --> 00:41:14,150 +The ICAO that is passed +to us up here, right? + +914 +00:41:14,150 --> 00:41:17,750 +This argument ICAO, I +want my predicate to be, + +915 +00:41:17,750 --> 00:41:22,750 +go look up this var, in the +database, with this value. + +916 +00:41:22,830 --> 00:41:26,700 +Then you can do things like, +and another one of them or + +917 +00:41:26,700 --> 00:41:29,150 +or something else equals something else. + +918 +00:41:29,150 --> 00:41:31,990 +And there's even more powerful +things where you can do + +919 +00:41:31,990 --> 00:41:35,900 +pattern matching and begins +with, and all kinds of things. + +920 +00:41:35,900 --> 00:41:38,940 +This predicate object, obviously, +if you're gonna do this + +921 +00:41:38,940 --> 00:41:41,060 +Core Data you're gonna +need to go look that up + +922 +00:41:41,060 --> 00:41:43,160 +in the documentation and +understand all the powerful + +923 +00:41:43,160 --> 00:41:46,090 +things you can do to go +figure out which objects + +924 +00:41:46,090 --> 00:41:47,563 +you want from the database. + +925 +00:41:48,820 --> 00:41:51,360 +The other thing that we want to know here + +926 +00:41:51,360 --> 00:41:54,400 +is the sortDescriptors. + +927 +00:41:54,400 --> 00:41:58,360 +Now, the sortDescriptors +are an Array of these things + +928 +00:41:58,360 --> 00:41:59,560 +called NSSortDescriptor, + +929 +00:42:01,460 --> 00:42:03,130 +and a SortDescriptor has two things. + +930 +00:42:03,130 --> 00:42:06,550 +One is the name of the +var you wanna sort by, + +931 +00:42:06,550 --> 00:42:08,070 +then actually, if I'm +looking for Airports, + +932 +00:42:08,070 --> 00:42:10,080 +I'm gonna sort them by location, + +933 +00:42:10,080 --> 00:42:11,910 +by the city that they're in. + +934 +00:42:11,910 --> 00:42:13,840 +And then the second thing +is whether you want them + +935 +00:42:13,840 --> 00:42:16,350 +ascending in order or descending. + +936 +00:42:16,350 --> 00:42:18,790 +And I do want this ascending. + +937 +00:42:18,790 --> 00:42:20,490 +Now, why is this important to have this + +938 +00:42:20,490 --> 00:42:22,300 +sortDescriptors here? + +939 +00:42:22,300 --> 00:42:24,640 +That's because when we look +up objects in the database, + +940 +00:42:24,640 --> 00:42:28,180 +they're gonna come back +as an Array, not as a Set, + +941 +00:42:28,180 --> 00:42:29,750 +but as an Array. + +942 +00:42:29,750 --> 00:42:31,850 +And it's an Array because they're ordered, + +943 +00:42:31,850 --> 00:42:33,780 +they're put in this order. + +944 +00:42:33,780 --> 00:42:35,120 +And why do we do that? + +945 +00:42:35,120 --> 00:42:38,100 +Why don't we just get a +Set instead of an Array? + +946 +00:42:38,100 --> 00:42:41,660 +Well, because sorting like +this can happen on the database + +947 +00:42:41,660 --> 00:42:45,040 +side very, very efficiently +and notice it's an Array of + +948 +00:42:45,040 --> 00:42:47,680 +SortDescriptor, so if you had +people in here and you had + +949 +00:42:47,680 --> 00:42:50,360 +first name and last name, you +could have a SortDescriptor + +950 +00:42:50,360 --> 00:42:52,473 +to sort by last name, and +then another SortDescriptor + +951 +00:42:52,473 --> 00:42:54,910 +to sub sort by first name. + +952 +00:42:54,910 --> 00:42:57,563 +That's why this is an +Array of SortDescriptors. + +953 +00:42:58,650 --> 00:43:00,760 +So that's all we need to do +to create this FetchRequest. + +954 +00:43:00,760 --> 00:43:04,210 +This is describing what we +want out of the database. + +955 +00:43:04,210 --> 00:43:06,800 +So how do we get it out of the database? + +956 +00:43:06,800 --> 00:43:08,230 +We use this little function, + +957 +00:43:08,230 --> 00:43:13,230 +let airports = context.fetch(request). + +958 +00:43:14,910 --> 00:43:19,409 +Now this context is one of these +things from back over here, + +959 +00:43:19,409 --> 00:43:23,310 +this context that we're +passing in our Environment, + +960 +00:43:23,310 --> 00:43:26,250 +this context here, that is +the window on the database. + +961 +00:43:26,250 --> 00:43:28,230 +If we wanna fetch something +out of the database, + +962 +00:43:28,230 --> 00:43:29,900 +we need that context. + +963 +00:43:29,900 --> 00:43:33,797 +So we're gonna have to pass +that along in with ICAO. + +964 +00:43:33,797 --> 00:43:37,020 +I'm gonna say here, context, context, + +965 +00:43:37,020 --> 00:43:39,790 +and then in withICAO, I'm +gonna have to have another + +966 +00:43:39,790 --> 00:43:41,737 +argument here, context. + +967 +00:43:41,737 --> 00:43:45,260 +And this context is of type +NSManagedObjectContext. + +968 +00:43:47,704 --> 00:43:51,290 +This fetch method though has +one other interesting thing is + +969 +00:43:51,290 --> 00:43:54,920 +that you have to try it +because it could fail, + +970 +00:43:54,920 --> 00:43:58,040 +no connection to the database +or something like that, + +971 +00:43:58,040 --> 00:44:00,010 +so it's possible it can fail. + +972 +00:44:00,010 --> 00:44:03,842 +Now, if you remember, if +we do try, we could do, + +973 +00:44:03,842 --> 00:44:05,460 +do and catch and try it in there, + +974 +00:44:05,460 --> 00:44:08,330 +and catch the error and see +what the error is and do things. + +975 +00:44:08,330 --> 00:44:11,500 +Here, if I try to do +this fetch and it fails, + +976 +00:44:11,500 --> 00:44:14,180 +I'm just gonna let this +whole thing return nil, + +977 +00:44:14,180 --> 00:44:16,930 +that's what try? hopefully +you remember that + +978 +00:44:16,930 --> 00:44:19,230 +from your reading about error handling. + +979 +00:44:19,230 --> 00:44:20,930 +That's what it does. + +980 +00:44:20,930 --> 00:44:22,210 +So this would be nil. + +981 +00:44:22,210 --> 00:44:24,090 +Now, if this doesn't fail, + +982 +00:44:24,090 --> 00:44:27,350 +but there is no Airport matching this, + +983 +00:44:27,350 --> 00:44:30,480 +then this is not gonna return nil or fail. + +984 +00:44:30,480 --> 00:44:33,100 +It's gonna return empty Array. + +985 +00:44:33,100 --> 00:44:36,470 +So calling fetch and +getting back an empty Array, + +986 +00:44:36,470 --> 00:44:38,820 +means I couldn't find it. + +987 +00:44:38,820 --> 00:44:40,010 +That's different from nil, + +988 +00:44:40,010 --> 00:44:43,270 +which means I had an error +trying to fetch this. + +989 +00:44:43,270 --> 00:44:45,500 +Now, if it does find it, + +990 +00:44:45,500 --> 00:44:48,720 +then this is going to return +an Array with all the Airport + +991 +00:44:48,720 --> 00:44:51,690 +objects in it, that match. + +992 +00:44:51,690 --> 00:44:54,100 +And this is a FetchRequest for Airports, + +993 +00:44:54,100 --> 00:44:56,650 +so this is gonna return +an Array of Airports. + +994 +00:44:56,650 --> 00:44:59,300 +Hopefully this never return +more than one Airport + +995 +00:44:59,300 --> 00:45:03,890 +because ICAO it's like, KSFO, +there should only be one + +996 +00:45:03,890 --> 00:45:04,840 +in the entire database. + +997 +00:45:04,840 --> 00:45:07,460 +That's why we're doing this +thing of looking it up first, + +998 +00:45:07,460 --> 00:45:08,803 +before we go create it. + +999 +00:45:10,140 --> 00:45:13,220 +So what I'm gonna do here is +kind of ignore the errors. + +1000 +00:45:13,220 --> 00:45:14,800 +If this comes back nil, + +1001 +00:45:14,800 --> 00:45:18,890 +then I'm gonna optional +default it to the empty Array. + +1002 +00:45:18,890 --> 00:45:20,880 +If I were shipping this as a real app, + +1003 +00:45:20,880 --> 00:45:23,100 +probably would catch this +error here and trying to figure + +1004 +00:45:23,100 --> 00:45:26,530 +out what am I going to do because +I fetched this Airport and + +1005 +00:45:26,530 --> 00:45:29,870 +it failed, probably if +this fetch fails though, + +1006 +00:45:29,870 --> 00:45:32,219 +all your Core Data stuff's +gonna start failing so + +1007 +00:45:32,219 --> 00:45:35,250 +you know, that would +be a top level failure + +1008 +00:45:35,250 --> 00:45:36,900 +that you'd have to handle anyway. + +1009 +00:45:38,010 --> 00:45:39,910 +So now this is going to be an Array. + +1010 +00:45:39,910 --> 00:45:41,430 +It's either gonna be an empty Array, + +1011 +00:45:41,430 --> 00:45:43,680 +if there was a failure or +if we couldn't find this, + +1012 +00:45:43,680 --> 00:45:46,120 +or it's gonna be an Array +of hopefully just one thing, + +1013 +00:45:46,120 --> 00:45:48,380 +which is the Airport object +that we've put in there + +1014 +00:45:48,380 --> 00:45:50,630 +in the past for this thing. + +1015 +00:45:50,630 --> 00:45:51,930 +So let's check those cases. + +1016 +00:45:51,930 --> 00:45:55,970 +First I'm gonna say, if I can let airport + +1017 +00:45:55,970 --> 00:46:00,970 +equal airports.first, first +element of the airport, + +1018 +00:46:03,020 --> 00:46:04,780 +then I found one. + +1019 +00:46:04,780 --> 00:46:08,970 +And so I'm just gonna +return it easy enough. + +1020 +00:46:08,970 --> 00:46:10,945 +This is the first part of this lookup + +1021 +00:46:10,945 --> 00:46:12,177 +It did this. + +1022 +00:46:12,177 --> 00:46:16,270 +And so now if it found, return it, + +1023 +00:46:16,270 --> 00:46:18,810 +otherwise we're in this case down here, + +1024 +00:46:18,810 --> 00:46:20,830 +where we couldn't find it, + +1025 +00:46:20,830 --> 00:46:23,720 +and now we need to create +one of these things + +1026 +00:46:23,720 --> 00:46:26,560 +and then fetch it from FlightAware. + +1027 +00:46:26,560 --> 00:46:29,280 +How do we do this? + +1028 +00:46:29,280 --> 00:46:33,920 +I'm going to create the airport +first with just this ICAO, + +1029 +00:46:33,920 --> 00:46:36,140 +I already have that information, +I don't have to fetch + +1030 +00:46:36,140 --> 00:46:38,670 +that from FlightAware it +was passed into me here. + +1031 +00:46:38,670 --> 00:46:39,943 +So let's create the airport. + +1032 +00:46:39,943 --> 00:46:43,830 +You can say, let airport = Airport. + +1033 +00:46:43,830 --> 00:46:46,370 +And of course we have to pass +that context because we have + +1034 +00:46:46,370 --> 00:46:50,390 +to really tell the system +which database to create this + +1035 +00:46:50,390 --> 00:46:53,437 +Airport in, but this creates an Airport, + +1036 +00:46:53,437 --> 00:46:57,920 +and then I'm gonna set +the Airport's icao var. + +1037 +00:46:57,920 --> 00:47:01,670 +This, our airport here has an icao var, + +1038 +00:47:01,670 --> 00:47:03,900 +how do I set this var? + +1039 +00:47:03,900 --> 00:47:08,720 +Amazingly I just say, .icao = icao. + +1040 +00:47:08,720 --> 00:47:13,720 +And again, Xcode has built +all the code behind this + +1041 +00:47:13,760 --> 00:47:16,373 +that makes this an +object that has this var, + +1042 +00:47:17,290 --> 00:47:19,760 +that doesn't seem to +still be recognizing that + +1043 +00:47:21,150 --> 00:47:22,453 +we can get it to do that. + +1044 +00:47:23,870 --> 00:47:26,883 +So now we've got that to compile here. + +1045 +00:47:28,070 --> 00:47:30,880 +So now we've created an Airport +and it doesn't have any of + +1046 +00:47:30,880 --> 00:47:34,030 +these other vars that we +want in here, like latitude, + +1047 +00:47:34,030 --> 00:47:35,260 +longitude, and all that, + +1048 +00:47:35,260 --> 00:47:37,400 +that information all +comes from FlightAware. + +1049 +00:47:37,400 --> 00:47:39,730 +So there's no way for me to say, + +1050 +00:47:39,730 --> 00:47:41,670 +airport.longitude = something right here. + +1051 +00:47:41,670 --> 00:47:43,830 +So it's just going to be nil. + +1052 +00:47:43,830 --> 00:47:45,520 +Those values are gonna +be nil and the database. + +1053 +00:47:45,520 --> 00:47:48,400 +Again, that's part of why +these vars are all Optionals, + +1054 +00:47:48,400 --> 00:47:50,060 +even the ICAO is an Optional, + +1055 +00:47:50,060 --> 00:47:52,630 +even though we're always +gonna be setting it here, + +1056 +00:47:52,630 --> 00:47:55,943 +it's an Optional because might +not be set in the database. + +1057 +00:47:57,040 --> 00:47:59,680 +So how do we fetch stuff from FlightAware? + +1058 +00:47:59,680 --> 00:48:02,050 +In this FlightAware code +that I have over here, + +1059 +00:48:02,050 --> 00:48:05,360 +one of the things we have +is an AirportInfo right here + +1060 +00:48:05,360 --> 00:48:08,660 +in the AirportInfo, +there's this struct called + +1061 +00:48:08,660 --> 00:48:10,627 +an AirportInfoRequest. + +1062 +00:48:10,627 --> 00:48:15,460 +And it has function fetch, +you give it the ICAO you want, + +1063 +00:48:15,460 --> 00:48:18,290 +and it will call you back later +once the information comes + +1064 +00:48:18,290 --> 00:48:20,250 +back with, from FlightAware, + +1065 +00:48:20,250 --> 00:48:22,870 +and give you an AirportInfo object. + +1066 +00:48:22,870 --> 00:48:27,520 +So an AirportInfo object looks like this, + +1067 +00:48:27,520 --> 00:48:30,290 +got the ICAO, longitude, +latitude all these things that + +1068 +00:48:30,290 --> 00:48:32,320 +we want to put in the database. + +1069 +00:48:32,320 --> 00:48:34,360 +I'm going to call a function here. + +1070 +00:48:34,360 --> 00:48:39,360 +self.update(from: +airportInfo, context: context) + +1071 +00:48:43,990 --> 00:48:47,670 +and this little static function +that we're going to do, + +1072 +00:48:47,670 --> 00:48:52,670 +static func update(from: airportInfo). + +1073 +00:48:54,740 --> 00:48:57,080 +I'll just call it info here. + +1074 +00:48:57,080 --> 00:48:59,980 +This is an AirportInfo +object from FlightAware. + +1075 +00:48:59,980 --> 00:49:01,670 +And then we need the context, of course, + +1076 +00:49:01,670 --> 00:49:05,370 +because we're going to be doing +something in the database. + +1077 +00:49:05,370 --> 00:49:07,150 +Anytime we're doing +something in the database, + +1078 +00:49:07,150 --> 00:49:10,000 +we need the context to +know which database. + +1079 +00:49:10,000 --> 00:49:13,070 +So in this update right here, +by the way, once we do this, + +1080 +00:49:13,070 --> 00:49:15,650 +I'm gonna return this Airport right away. + +1081 +00:49:15,650 --> 00:49:17,790 +Now, when I first return this Airport, + +1082 +00:49:17,790 --> 00:49:19,860 +it's only gonna have the ICAO in it. + +1083 +00:49:19,860 --> 00:49:20,900 +It's not gonna have all this. + +1084 +00:49:20,900 --> 00:49:23,430 +This is asynchronous, +it's happening later. + +1085 +00:49:23,430 --> 00:49:26,570 +So when someone says, give +me the Airport with an ICAO + +1086 +00:49:26,570 --> 00:49:27,810 +and I've never seen it before, + +1087 +00:49:27,810 --> 00:49:30,380 +I'm gonna give them +back a mostly empty one + +1088 +00:49:30,380 --> 00:49:31,813 +that just has ICAO. + +1089 +00:49:32,750 --> 00:49:34,370 +So I shouldn't, + +1090 +00:49:34,370 --> 00:49:37,180 +I'm gonna have to make my +Airport be pretty tolerant. + +1091 +00:49:37,180 --> 00:49:39,360 +All my codes are going to be +tolerant of all those other + +1092 +00:49:39,360 --> 00:49:42,150 +fields being nil, which is +fine they're just gonna have to + +1093 +00:49:42,150 --> 00:49:43,573 +check to see if they're nil. + +1094 +00:49:44,700 --> 00:49:47,620 +But this one we can pretty +much always count on not being + +1095 +00:49:47,620 --> 00:49:49,050 +nil, and we're gonna talk +about how we're gonna deal + +1096 +00:49:49,050 --> 00:49:50,443 +with that in a second. + +1097 +00:49:52,080 --> 00:49:54,420 +So update, how do we do +this update right here? + +1098 +00:49:54,420 --> 00:49:56,923 +So this is happening something +time later, it comes back. + +1099 +00:49:56,923 --> 00:50:01,923 +Let me see if I can let the +ICAO equal this info's ICAO. + +1100 +00:50:03,420 --> 00:50:05,490 +So this is the info coming +back from FlightAware, + +1101 +00:50:05,490 --> 00:50:08,270 +I'm gonna see if I can +get the ICAO out of there, + +1102 +00:50:08,270 --> 00:50:10,340 +which I should be able to do. + +1103 +00:50:10,340 --> 00:50:14,060 +Then I'm going to look this airport up + +1104 +00:50:14,060 --> 00:50:18,917 +by calling my own withICAO +function in this context, + +1105 +00:50:21,850 --> 00:50:24,570 +'cause this is happening +sometime later, right? + +1106 +00:50:24,570 --> 00:50:25,557 +This closure happened sometime later, + +1107 +00:50:25,557 --> 00:50:28,580 +so now I'm gonna go back +and call this again, + +1108 +00:50:28,580 --> 00:50:31,530 +to get this Airport that +I created earlier actually + +1109 +00:50:31,530 --> 00:50:34,530 +the one that just has the +ICAO and I'm gonna go back + +1110 +00:50:34,530 --> 00:50:37,160 +and get it 'cause this +is all happening later. + +1111 +00:50:37,160 --> 00:50:39,690 +And then I'm just going +to set all the fields. + +1112 +00:50:39,690 --> 00:50:44,690 +The latitude = +info.latitude, and longitude, + +1113 +00:50:49,010 --> 00:50:51,310 +longitude, you gotta +type all these fields in. + +1114 +00:50:53,600 --> 00:50:58,150 +Next step I wanna take here +is to save this information + +1115 +00:50:58,150 --> 00:50:59,913 +into the database. + +1116 +00:51:00,800 --> 00:51:05,193 +Now that can be done by asking +the context to do a save. + +1117 +00:51:06,310 --> 00:51:09,390 +But you can see here that +the context save throws, + +1118 +00:51:09,390 --> 00:51:11,210 +see where it says throws right there. + +1119 +00:51:11,210 --> 00:51:12,470 +Anytime you see throws, + +1120 +00:51:12,470 --> 00:51:17,110 +that means that this is a +function you have to try. + +1121 +00:51:17,110 --> 00:51:18,690 +And I'm happy to try this. + +1122 +00:51:18,690 --> 00:51:20,623 +And if it fails, just do nothing. + +1123 +00:51:21,800 --> 00:51:25,890 +Now this is not all the +vars on my Airport though. + +1124 +00:51:25,890 --> 00:51:27,870 +If I go back and look at my Airport, + +1125 +00:51:27,870 --> 00:51:31,100 +I've got all these vars, +but, what about these? + +1126 +00:51:31,100 --> 00:51:32,583 +flightsFrom a flightsTo? + +1127 +00:51:33,620 --> 00:51:37,550 +Well flightsFrom and flightsTo, +can be set from either side, + +1128 +00:51:37,550 --> 00:51:41,090 +you can either set it by having +a Flight set its destination + +1129 +00:51:41,090 --> 00:51:45,050 +to an Airport, and that's going +to cause the flightsTo Set, + +1130 +00:51:45,050 --> 00:51:47,402 +to get an Airport added +to it automatically. + +1131 +00:51:47,402 --> 00:51:48,450 +You don't have to do anything. + +1132 +00:51:48,450 --> 00:51:49,283 +And vice versa. + +1133 +00:51:49,283 --> 00:51:52,430 +If you add something to this +flightsTo, on this side, + +1134 +00:51:52,430 --> 00:51:56,350 +it's going to cause that Flight +to point back the other way. + +1135 +00:51:56,350 --> 00:51:57,183 +So that's pretty cool. + +1136 +00:51:57,183 --> 00:51:58,913 +That's automatically managed for us. + +1137 +00:52:00,910 --> 00:52:03,720 +Now what about one other +thing we wanna do here. + +1138 +00:52:03,720 --> 00:52:05,670 +So we've created this thing. + +1139 +00:52:05,670 --> 00:52:06,960 +We saved it. + +1140 +00:52:06,960 --> 00:52:11,960 +Remember that these Airports +are ObservableObjects. + +1141 +00:52:12,160 --> 00:52:14,040 +They're a little mini ViewModels. + +1142 +00:52:14,040 --> 00:52:16,180 +So I'm doing a wholesale +update right here. + +1143 +00:52:16,180 --> 00:52:20,250 +I'm going to actually tell +this Airport to fire off its + +1144 +00:52:20,250 --> 00:52:22,363 +objectWillChange.send(). + +1145 +00:52:24,210 --> 00:52:26,690 +That's gonna cause any Views +that are looking at this + +1146 +00:52:26,690 --> 00:52:30,260 +Airport right now to redraw +themselves and hopefully pick up + +1147 +00:52:30,260 --> 00:52:32,710 +this new information if +they depend on any of it. + +1148 +00:52:33,623 --> 00:52:34,730 +Hopefully we can do another thing too. + +1149 +00:52:34,730 --> 00:52:39,100 +I'm gonna have the Airport's flightsTo, + +1150 +00:52:39,100 --> 00:52:44,100 +I'm gonna have each of +them forEach do their + +1151 +00:52:44,266 --> 00:52:47,340 +objectWillChange.send(). + +1152 +00:52:47,340 --> 00:52:49,540 +Lemme do the same thing +for my flightsFrom. + +1153 +00:52:55,070 --> 00:52:59,550 +Now, this doesn't work because +of what I was saying before + +1154 +00:52:59,550 --> 00:53:03,110 +that these flightsTo and +flightFrom our NSSets, + +1155 +00:53:03,110 --> 00:53:06,030 +you see that, the value of type NSSet. + +1156 +00:53:06,030 --> 00:53:10,750 +So you can't tell an NSSet +Optional here to do this. + +1157 +00:53:10,750 --> 00:53:12,570 +And even if I make it non-Optional, + +1158 +00:53:12,570 --> 00:53:14,460 +that's not gonna fix the problem either, + +1159 +00:53:14,460 --> 00:53:18,490 +because it's not only an +NSSet, it's an NSSet of Any. + +1160 +00:53:18,490 --> 00:53:21,120 +So it doesn't even know +that these flightsTo, + +1161 +00:53:21,120 --> 00:53:24,440 +are actually Flights, Flight objects. + +1162 +00:53:24,440 --> 00:53:29,440 +So this solution here requires +a little bit of what I call + +1163 +00:53:29,635 --> 00:53:33,130 +syntactic sugar not added by the compiler, + +1164 +00:53:33,130 --> 00:53:34,570 +but something we're gonna add. + +1165 +00:53:34,570 --> 00:53:37,700 +I'm going to make +flightsTo and flightsFrom, + +1166 +00:53:37,700 --> 00:53:41,810 +be little computed var, flightsTo, + +1167 +00:53:41,810 --> 00:53:46,453 +I'm gonna have a Set of Flights +and I'm gonna have a get and + +1168 +00:53:47,550 --> 00:53:52,003 +a set and the same thing with flightsFrom. + +1169 +00:53:57,160 --> 00:54:01,090 +Now, how am I gonna do +this flightsFrom and To + +1170 +00:54:01,090 --> 00:54:04,970 +as computed vars because +I already have flightsTo + +1171 +00:54:04,970 --> 00:54:08,315 +and flightsFrom vars from over here, + +1172 +00:54:08,315 --> 00:54:10,870 +and my airport already has +these var, these are vars. + +1173 +00:54:10,870 --> 00:54:13,720 +So I'm gonna rename these vars over here, + +1174 +00:54:13,720 --> 00:54:15,673 +to put a little underbar after them. + +1175 +00:54:16,584 --> 00:54:18,220 +And this is just something kind of, + +1176 +00:54:18,220 --> 00:54:22,560 +I like to do when I have things +that are set right here and + +1177 +00:54:22,560 --> 00:54:24,400 +I'm gonna do it for other things later, + +1178 +00:54:24,400 --> 00:54:26,760 +where the thing in the +database is almost exactly + +1179 +00:54:26,760 --> 00:54:28,050 +what I want, but not quite. + +1180 +00:54:28,050 --> 00:54:33,050 +So this is a set of these +Any from kind of Objective-C + +1181 +00:54:33,310 --> 00:54:35,280 +version of this thing. + +1182 +00:54:35,280 --> 00:54:40,280 +And I'm gonna have my +flightsTo get by returning the + +1183 +00:54:40,420 --> 00:54:45,420 +flightsTo_ as a Set of Flight. + +1184 +00:54:49,230 --> 00:54:54,230 +And oh, by the way, if that is not set, + +1185 +00:54:54,230 --> 00:54:56,971 +I'm gonna return an empty Set of Flight. + +1186 +00:54:56,971 --> 00:54:58,880 +So here, I've kind of +done two things at once. + +1187 +00:54:58,880 --> 00:55:03,110 +I've converted flightsTo, to be, + +1188 +00:55:03,110 --> 00:55:05,820 +not be an NSSet and +instead be a Set of Flight, + +1189 +00:55:05,820 --> 00:55:08,380 +and I've also checked to see +a flightsTo might be nil, + +1190 +00:55:08,380 --> 00:55:12,133 +and if it is returned +an empty Set instead. + +1191 +00:55:13,250 --> 00:55:15,370 +So setting it is easy as well. + +1192 +00:55:15,370 --> 00:55:20,370 +flightsTo_ = newValue as NSSet. + +1193 +00:55:22,660 --> 00:55:26,920 +So the Objective-C versions +of Set and the Swift version + +1194 +00:55:26,920 --> 00:55:30,380 +Sets can be as-ed, this is +typecasting, and hopefully you + +1195 +00:55:30,380 --> 00:55:32,410 +remember from reading again, + +1196 +00:55:32,410 --> 00:55:35,660 +they can be as-ed directly as each other, + +1197 +00:55:35,660 --> 00:55:37,150 +which is really a cool feature, + +1198 +00:55:37,150 --> 00:55:41,363 +very big compatibility +feature to have that work. + +1199 +00:55:42,530 --> 00:55:46,270 +So my flightsFrom is pretty +much exactly the same thing. + +1200 +00:55:46,270 --> 00:55:48,733 +We're doing flightsFrom here, + +1201 +00:55:49,983 --> 00:55:51,100 +and flightsFrom. + +1202 +00:55:54,180 --> 00:55:55,400 +That's it, everybody hopefully understand, + +1203 +00:55:55,400 --> 00:55:59,300 +I'm just trying to make my +code here look really clean + +1204 +00:55:59,300 --> 00:56:03,220 +and sweet by making it be Set +of Flight instead of being + +1205 +00:56:03,220 --> 00:56:06,663 +this NSSet of Any and +possibly nil as well. + +1206 +00:56:09,470 --> 00:56:14,470 +So that's all I think I need +to do here to create an Airport + +1207 +00:56:14,580 --> 00:56:16,220 +or find one that's existing. + +1208 +00:56:16,220 --> 00:56:20,557 +So if I go back over to +my SceneDelegate here, + +1209 +00:56:21,460 --> 00:56:24,020 +oh, look at that, all +that code just compiles + +1210 +00:56:24,020 --> 00:56:25,350 +perfectly fine here. + +1211 +00:56:25,350 --> 00:56:29,000 +Now this thing that I +did with Airport here, + +1212 +00:56:29,000 --> 00:56:32,730 +with flightsTo, again, not only +switching from Set to NSSet + +1213 +00:56:32,730 --> 00:56:35,480 +but also checking to see if it's nil. + +1214 +00:56:35,480 --> 00:56:38,650 +So this flightsTo at worst +is ever an empty Set, + +1215 +00:56:38,650 --> 00:56:39,810 +not nil. + +1216 +00:56:39,810 --> 00:56:42,760 +I like to do that with +all my other vars too, + +1217 +00:56:42,760 --> 00:56:44,710 +that can't really be nil. + +1218 +00:56:44,710 --> 00:56:47,007 +For example, let's go +look in Airport here, + +1219 +00:56:47,007 --> 00:56:51,680 +and see which of these can +never, or should never be nil. + +1220 +00:56:51,680 --> 00:56:53,790 +Well, actually, any of these can be nil, + +1221 +00:56:53,790 --> 00:56:56,590 +and they're all gonna be nil +while I'm doing my fetch, + +1222 +00:56:56,590 --> 00:57:00,950 +except for not this one, icao +never really should be nil. + +1223 +00:57:00,950 --> 00:57:04,130 +So I'm gonna put an underbar after it. + +1224 +00:57:04,130 --> 00:57:05,620 +And then in my extension over here, + +1225 +00:57:05,620 --> 00:57:08,180 +and I actually have +this commented out here + +1226 +00:57:08,180 --> 00:57:10,370 +so that we can speed this along. + +1227 +00:57:10,370 --> 00:57:14,240 +I'm going to create a similar sort of var, + +1228 +00:57:14,240 --> 00:57:16,850 +this one's not doing the Set NSSet thing, + +1229 +00:57:16,850 --> 00:57:21,320 +but it's just making this +thing be not Optional anymore. + +1230 +00:57:21,320 --> 00:57:24,150 +So it's taking the underbar +version, make it not Optional. + +1231 +00:57:24,150 --> 00:57:27,181 +Now I have a to do here you +see that when my app ships, + +1232 +00:57:27,181 --> 00:57:29,820 +maybe I wanna do something else here, + +1233 +00:57:29,820 --> 00:57:30,870 +when this thing is nil + +1234 +00:57:30,870 --> 00:57:32,490 +because it's really an error condition. + +1235 +00:57:32,490 --> 00:57:35,640 +This should never happen because +when I create an Airport, + +1236 +00:57:35,640 --> 00:57:37,940 +the very first thing +I do on the next line, + +1237 +00:57:37,940 --> 00:57:41,420 +is set this icao this +can really never happen + +1238 +00:57:41,420 --> 00:57:42,480 +that this is nil. + +1239 +00:57:42,480 --> 00:57:45,650 +If this did, it's some +error condition going on. + +1240 +00:57:45,650 --> 00:57:49,160 +So I could possibly try and +handle this error condition + +1241 +00:57:49,160 --> 00:57:52,500 +better than just crashing +because we know that exclamation + +1242 +00:57:52,500 --> 00:57:54,640 +point is just gonna crash. + +1243 +00:57:54,640 --> 00:57:57,350 +But certainly for this demo, +and while I'm in development, + +1244 +00:57:57,350 --> 00:57:59,730 +maybe I want this to crash +while I'm in development. + +1245 +00:57:59,730 --> 00:58:02,650 +I wanna see the cases under +which I can get this kind of + +1246 +00:58:02,650 --> 00:58:05,560 +corrupted database to happen, + +1247 +00:58:05,560 --> 00:58:08,037 +if ever, may never happen +that this can happen. + +1248 +00:58:09,278 --> 00:58:10,780 +I've also added some +other things down here, + +1249 +00:58:10,780 --> 00:58:12,180 +a friendly name for the Airport, + +1250 +00:58:12,180 --> 00:58:15,350 +just by looking at it's name +and location carrying that. + +1251 +00:58:15,350 --> 00:58:18,090 +I've also made Airports +Identifiable and Comparable, + +1252 +00:58:18,090 --> 00:58:21,250 +it's usually a nice thing to +do with your objects from Core + +1253 +00:58:21,250 --> 00:58:23,330 +Data so you can put them in dictionaries + +1254 +00:58:23,330 --> 00:58:25,033 +and Sets and things like that. + +1255 +00:58:26,510 --> 00:58:29,080 +So we've done a lot of great +stuff here with Airport, + +1256 +00:58:29,080 --> 00:58:30,700 +and we've learned a +lot about the Core Data + +1257 +00:58:30,700 --> 00:58:31,710 +just from doing Airport. + +1258 +00:58:31,710 --> 00:58:35,990 +We know how to fetch them, we +know how to create new ones, + +1259 +00:58:35,990 --> 00:58:39,800 +we know how to do this little +thing where we make our sets + +1260 +00:58:39,800 --> 00:58:44,340 +look a little nicer, we know +how to kind of cover our + +1261 +00:58:44,340 --> 00:58:45,710 +can be Optional ones. + +1262 +00:58:45,710 --> 00:58:48,370 +And in fact, let's do this +little can-be-Optional cover + +1263 +00:58:48,370 --> 00:58:49,860 +for our other things as well. + +1264 +00:58:49,860 --> 00:58:51,563 +We have Airline over here. + +1265 +00:58:54,810 --> 00:58:57,130 +So I've done the same thing +here, now for Airline, + +1266 +00:58:57,130 --> 00:59:00,764 +I want code, name, shortname, +and then of course, + +1267 +00:59:00,764 --> 00:59:03,580 +we're gonna do the flights Set magic here. + +1268 +00:59:03,580 --> 00:59:05,760 +So code, name, short name, +flights, that's pretty much all + +1269 +00:59:05,760 --> 00:59:08,963 +the things down here in Airline, + +1270 +00:59:10,761 --> 00:59:12,663 +to make that an underbar, name, + +1271 +00:59:15,040 --> 00:59:19,990 +underbar and shortname, +underbar and flights also here, + +1272 +00:59:19,990 --> 00:59:23,350 +it's underbar, and how about Flight? + +1273 +00:59:23,350 --> 00:59:25,050 +So I do the same thing for Flights, + +1274 +00:59:25,050 --> 00:59:27,000 +which we haven't even looked at Flight. + +1275 +00:59:28,300 --> 00:59:29,133 +All right. + +1276 +00:59:29,133 --> 00:59:30,860 +So Flight, I made the arrival, + +1277 +00:59:30,860 --> 00:59:34,370 +the destination, origin, airport, +the airline and the ident, + +1278 +00:59:34,370 --> 00:59:36,840 +all of these things, can't be nil, and + +1279 +00:59:36,840 --> 00:59:38,990 +then I added this nice +little number thing. + +1280 +00:59:40,010 --> 00:59:43,370 +Let's go over here to +our data Model for Flight + +1281 +00:59:43,370 --> 00:59:46,480 +and aircraft is fine, arrival, + +1282 +00:59:46,480 --> 00:59:49,030 +make that arrival time can't be nil. + +1283 +00:59:49,030 --> 00:59:52,000 +departure time can be +nil, filed could be nil, + +1284 +00:59:52,000 --> 00:59:54,220 +ident cannot be nil. + +1285 +00:59:54,220 --> 00:59:57,640 +And then all these relationships +we're going to just protect + +1286 +00:59:57,640 --> 00:59:58,797 +them against being nil. + +1287 +01:00:02,090 --> 01:00:03,320 +So that's all we've done there. + +1288 +01:00:03,320 --> 01:00:04,810 +This just makes our code nicer. + +1289 +01:00:04,810 --> 01:00:08,510 +We don't have to be constantly +checking to see if the ident + +1290 +01:00:08,510 --> 01:00:10,720 +is not nil because a Flight's ident + +1291 +01:00:10,720 --> 01:00:12,650 +really can never copy nil. + +1292 +01:00:12,650 --> 01:00:14,160 +If the Flight didn't have an ident, + +1293 +01:00:14,160 --> 01:00:15,723 +it doesn't even exist really. + +1294 +01:00:15,723 --> 01:00:18,350 +And same thing arrival time, +Flights have to have at least + +1295 +01:00:18,350 --> 01:00:20,320 +an estimated arrival time. + +1296 +01:00:20,320 --> 01:00:22,050 +Now, one thing to be careful of + +1297 +01:00:22,050 --> 01:00:26,500 +when you go through and do +this kind of getting rid of the + +1298 +01:00:26,500 --> 01:00:30,270 +Optional mess of things, +is that your fetches, + +1299 +01:00:30,270 --> 01:00:31,970 +like this fetch right here, + +1300 +01:00:31,970 --> 01:00:35,120 +it still has to use the underbar version, + +1301 +01:00:35,120 --> 01:00:39,160 +it can't not use an +underbar version for that. + +1302 +01:00:39,160 --> 01:00:41,690 +Anything you make not have the underbar, + +1303 +01:00:41,690 --> 01:00:44,860 +this request right here, this predicate, + +1304 +01:00:44,860 --> 01:00:48,300 +it's doing fetching on +fields in the database, + +1305 +01:00:48,300 --> 01:00:50,920 +not vars in your code down here. + +1306 +01:00:50,920 --> 01:00:52,420 +It's actually fetching in the database. + +1307 +01:00:52,420 --> 01:00:54,460 +So this has to be a field in the database. + +1308 +01:00:54,460 --> 01:00:56,140 +Same thing with SortDescriptors. + +1309 +01:00:56,140 --> 01:00:59,420 +Now the location, if we +look back here at Airport, + +1310 +01:00:59,420 --> 01:01:02,400 +this location, we didn't underbar that. + +1311 +01:01:02,400 --> 01:01:04,000 +So we don't want the underbar there, + +1312 +01:01:04,000 --> 01:01:07,050 +means we don't want the +underbar here either. + +1313 +01:01:07,050 --> 01:01:11,530 +So we fixed all of that problem +that we originally had here + +1314 +01:01:11,530 --> 01:01:14,400 +in SceneDelegate, where we +were trying to create a Flight + +1315 +01:01:14,400 --> 01:01:18,170 +search with KSFO instead, we +just made ourselves an Airport + +1316 +01:01:18,170 --> 01:01:21,242 +object and pass that in +so that our FlightSearch + +1317 +01:01:21,242 --> 01:01:24,663 +was now taking a destination +that was an Airport. + +1318 +01:01:25,890 --> 01:01:29,600 +Let's continue to chase after +our bugs over here that we + +1319 +01:01:29,600 --> 01:01:33,030 +introduced by making this +all be object-oriented. + +1320 +01:01:33,030 --> 01:01:35,770 +This one says, binary +operator == between String and + +1321 +01:01:35,770 --> 01:01:37,001 +Airport of course. + +1322 +01:01:37,001 --> 01:01:38,295 +Another one of these is where's that, + +1323 +01:01:38,295 --> 01:01:40,280 +that's in FlightFetcher, +so I'm clicking on that, + +1324 +01:01:40,280 --> 01:01:41,860 +so this is part of the +private implementation + +1325 +01:01:41,860 --> 01:01:43,350 +of FlightFetcher. + +1326 +01:01:43,350 --> 01:01:46,660 +Yeah, of course, FlightFetcher +is all non-object-oriented + +1327 +01:01:46,660 --> 01:01:49,110 +based on Strings and fetching Strings. + +1328 +01:01:49,110 --> 01:01:51,360 +So FlightFetcher itself is just gonna be + +1329 +01:01:51,360 --> 01:01:53,820 +completely useless. + +1330 +01:01:53,820 --> 01:01:56,570 +So let's go back to our +FlightEnrouteView and go + +1331 +01:01:56,570 --> 01:01:58,250 +look for FlightFetcher. + +1332 +01:01:58,250 --> 01:02:00,650 +Here's where we use it in our Flight list. + +1333 +01:02:00,650 --> 01:02:03,310 +Fetch Flights, obviously +for our Flight list, + +1334 +01:02:03,310 --> 01:02:04,320 +this whole thing is useless. + +1335 +01:02:04,320 --> 01:02:07,120 +I'm just gonna delete all +this FlightFetcher code + +1336 +01:02:07,120 --> 01:02:09,333 +because we can't use any of it anymore. + +1337 +01:02:10,450 --> 01:02:12,800 +So how do we do the equivalent though? + +1338 +01:02:12,800 --> 01:02:16,960 +In Core Data, we want +to go fetch all of those + +1339 +01:02:16,960 --> 01:02:19,323 +Flights and ForEach through them. + +1340 +01:02:20,190 --> 01:02:23,027 +Well, it's pretty cool +integration here between Core Data + +1341 +01:02:23,027 --> 01:02:26,220 +and SwiftUI, I'm actually +gonna create a var + +1342 +01:02:26,220 --> 01:02:28,433 +for those Flights right here. + +1343 +01:02:29,730 --> 01:02:34,200 +And I'm gonna do that var +using a property wrapper + +1344 +01:02:34,200 --> 01:02:36,537 +called @FetchRequest. + +1345 +01:02:37,520 --> 01:02:38,690 +And it takes some arguments + +1346 +01:02:38,690 --> 01:02:40,610 +which we'll talk about in a second. + +1347 +01:02:40,610 --> 01:02:44,740 +And this return value of +something that is using this + +1348 +01:02:44,740 --> 01:02:48,520 +property wrapper is +called a FetchedResults, + +1349 +01:02:48,520 --> 01:02:49,800 +many times it don't care, + +1350 +01:02:49,800 --> 01:02:53,990 +which is the kind of thing +it's fetching, which is Flight. + +1351 +01:02:53,990 --> 01:02:56,470 +So this Flight, remember +that's our Flight that we're + +1352 +01:02:56,470 --> 01:02:59,220 +creating here from our database. + +1353 +01:02:59,220 --> 01:03:02,840 +And we're gonna issue +some sort of FetchRequest + +1354 +01:03:02,840 --> 01:03:04,010 +to get some flights. + +1355 +01:03:04,010 --> 01:03:07,340 +And this var is going to +be this FetchedResults. + +1356 +01:03:07,340 --> 01:03:10,200 +Now, what is a FetchedResults of Flight? + +1357 +01:03:10,200 --> 01:03:12,570 +It's not quite an Array of Flights, + +1358 +01:03:12,570 --> 01:03:14,260 +although it is a Collection. + +1359 +01:03:14,260 --> 01:03:15,827 +So it'll work to put it right here, + +1360 +01:03:15,827 --> 01:03:17,870 +and for each it's worth just mine, + +1361 +01:03:17,870 --> 01:03:20,530 +because this is essentially a Collection. + +1362 +01:03:20,530 --> 01:03:22,520 +And that's what ForEach is looking for, + +1363 +01:03:22,520 --> 01:03:25,750 +a Collection of Identifiable +objects basically. + +1364 +01:03:25,750 --> 01:03:30,590 +This is essentially the result +of this FetchRequest as a + +1365 +01:03:30,590 --> 01:03:33,430 +bunch of Flights, which +is exactly what we want. + +1366 +01:03:33,430 --> 01:03:36,260 +Now, how do we specify +this FetchRequest here? + +1367 +01:03:36,260 --> 01:03:38,940 +We essentially have to give it +the exact same information we + +1368 +01:03:38,940 --> 01:03:42,430 +did over here in Airport, each +one of these FetchRequests. + +1369 +01:03:42,430 --> 01:03:45,710 +So we have to give it a predicate, +what this entity name is, + +1370 +01:03:45,710 --> 01:03:48,720 +what the SortDescriptors, +and you can do that, + +1371 +01:03:48,720 --> 01:03:50,190 +there is something I think it's called, + +1372 +01:03:50,190 --> 01:03:53,727 +yeah, here it is entity you +would say something like + +1373 +01:03:53,727 --> 01:03:56,850 +Flight.entity() and then +there are SortDescriptors, + +1374 +01:03:56,850 --> 01:03:58,110 +you would put those. + +1375 +01:03:58,110 --> 01:04:01,070 +And then there's also +another one predicate, + +1376 +01:04:01,070 --> 01:04:02,120 +and you put those, + +1377 +01:04:02,120 --> 01:04:05,120 +but we're not gonna do that +because we really can't. + +1378 +01:04:05,120 --> 01:04:09,050 +The problem is, what are +we trying to fetch here? + +1379 +01:04:09,050 --> 01:04:13,240 +We're trying to fetch things +that match this flight search. + +1380 +01:04:13,240 --> 01:04:16,390 +So unfortunately this flight +search is passed to us, + +1381 +01:04:16,390 --> 01:04:20,706 +we can't use it in here to initialize this + +1382 +01:04:20,706 --> 01:04:23,220 +property, wrappers struct. + +1383 +01:04:23,220 --> 01:04:25,530 +So we're gonna have to do it in here. + +1384 +01:04:25,530 --> 01:04:29,527 +And we know exactly how to +initialize property wrapper + +1385 +01:04:29,527 --> 01:04:32,630 +structs, we use the +underbar version of it. + +1386 +01:04:32,630 --> 01:04:34,103 +So _flights, + +1387 +01:04:34,103 --> 01:04:36,220 +there's the under bar +version of this Flight, + +1388 +01:04:36,220 --> 01:04:40,040 +that's this struct, I'm +gonna set that equal to + +1389 +01:04:40,040 --> 01:04:43,760 +a FetchRequest that's one of +these structs that I'm gonna + +1390 +01:04:43,760 --> 01:04:46,803 +create with a FetchRequest. + +1391 +01:04:48,910 --> 01:04:51,010 +So this is one of the +constructors for creating a + +1392 +01:04:51,010 --> 01:04:53,180 +FetchRequest, I told you, +there was the other one here, + +1393 +01:04:53,180 --> 01:04:55,300 +that took the entity and all that. + +1394 +01:04:55,300 --> 01:04:59,650 +But one of the choices +here also is FetchRequest. + +1395 +01:04:59,650 --> 01:05:01,890 +So I'm just going to +give it a FetchRequest, + +1396 +01:05:01,890 --> 01:05:04,950 +and this FetchRequest I'm +gonna do exactly the same thing + +1397 +01:05:04,950 --> 01:05:07,630 +I did over here when we +did the Airport look up, + +1398 +01:05:07,630 --> 01:05:11,443 +lemme get this document and +copy and paste it, so similar. + +1399 +01:05:13,130 --> 01:05:15,350 +And here this time, we're +not looking up Airports, + +1400 +01:05:15,350 --> 01:05:17,163 +we're looking up Flights. + +1401 +01:05:20,870 --> 01:05:23,850 +So here we're not looking +up the ICAO, of course, + +1402 +01:05:23,850 --> 01:05:27,470 +we're looking at the destination +airport of this thing, + +1403 +01:05:27,470 --> 01:05:29,270 +which we underbar-ed because +it doesn't make sense to have a + +1404 +01:05:29,270 --> 01:05:30,480 +Flight without a destination. + +1405 +01:05:30,480 --> 01:05:33,650 +So that's why we made it +so that it would never be + +1406 +01:05:33,650 --> 01:05:34,483 +Optional there. + +1407 +01:05:34,483 --> 01:05:36,030 +And what is the destination? + +1408 +01:05:36,030 --> 01:05:38,600 +It's the FlightSearch +that we're being passed, + +1409 +01:05:38,600 --> 01:05:40,830 +its destination, this FlightSearch, + +1410 +01:05:40,830 --> 01:05:42,840 +it's a FlightSearch +object, we changed that, + +1411 +01:05:42,840 --> 01:05:45,000 +so its destination's an Airport. + +1412 +01:05:45,000 --> 01:05:48,250 +So now we are doing a fetch +here where we're looking for + +1413 +01:05:48,250 --> 01:05:51,840 +destination equals that Airport. + +1414 +01:05:51,840 --> 01:05:55,320 +Now we have other SortDescriptor obviously + +1415 +01:05:55,320 --> 01:05:57,690 +let's sort by, I think our arrival time + +1416 +01:05:58,530 --> 01:06:01,600 +is probably the best thing +to sort our Flights by. + +1417 +01:06:01,600 --> 01:06:04,500 +Now we have other predicate +things we wanna search for + +1418 +01:06:04,500 --> 01:06:07,480 +in here besides the destination, +like origin Airline, + +1419 +01:06:07,480 --> 01:06:10,012 +inTheAir but we'll do that a little bit + +1420 +01:06:10,012 --> 01:06:11,470 +when we get our FilterFlights working. + +1421 +01:06:11,470 --> 01:06:13,950 +So for now we're just going +to look for all the Flights + +1422 +01:06:13,950 --> 01:06:16,110 +to this destination. + +1423 +01:06:16,110 --> 01:06:19,530 +Now you see that I've typed +the three lines of code here, + +1424 +01:06:19,530 --> 01:06:21,900 +I typed the same three +lines of code over here. + +1425 +01:06:21,900 --> 01:06:23,850 +They're very, very similar. + +1426 +01:06:23,850 --> 01:06:26,240 +You really kind of use them all the time, + +1427 +01:06:26,240 --> 01:06:28,330 +'cause you're searching +for objects all the time. + +1428 +01:06:28,330 --> 01:06:33,230 +I like to make little +functions in my extensions + +1429 +01:06:33,230 --> 01:06:36,960 +to these that do these +three lines of code for me. + +1430 +01:06:36,960 --> 01:06:38,640 +So instead of doing these +three lines to code, + +1431 +01:06:38,640 --> 01:06:43,640 +I'm gonna use some code that +I put down here to do this. + +1432 +01:06:44,570 --> 01:06:46,910 +And it just makes a +FetchRequest with a predicate + +1433 +01:06:46,910 --> 01:06:49,490 +and it automatically picks +the right SortDescriptor. + +1434 +01:06:49,490 --> 01:06:52,330 +It does this little +entityName thing to create the + +1435 +01:06:52,330 --> 01:06:53,360 +FetchRequest in the first place. + +1436 +01:06:53,360 --> 01:06:56,357 +And then it just plops the +predicate that you want in there. + +1437 +01:06:56,357 --> 01:06:59,280 +And that changes this three +lines of code up here to a + +1438 +01:06:59,280 --> 01:07:03,430 +single line of code, let +request equal a fetchRequest + +1439 +01:07:04,630 --> 01:07:07,110 +where the predicate is NSPredicate, + +1440 +01:07:07,110 --> 01:07:12,110 +and our predicate here was "icao_ = %@" + +1441 +01:07:12,120 --> 01:07:14,780 +of this ICAO. + +1442 +01:07:14,780 --> 01:07:16,790 +So now I don't have to +do the SortDescriptors + +1443 +01:07:16,790 --> 01:07:17,830 +and all that stuff. + +1444 +01:07:17,830 --> 01:07:20,350 +It just makes this code simpler. + +1445 +01:07:20,350 --> 01:07:22,400 +And let me do the same thing for Flights. + +1446 +01:07:25,230 --> 01:07:28,400 +There is FetchRequest for +Flight, sorts by arrival. + +1447 +01:07:28,400 --> 01:07:30,520 +It's got the right entity, name here, + +1448 +01:07:30,520 --> 01:07:32,557 +I'm gonna do the same thing for Airline. + +1449 +01:07:32,557 --> 01:07:36,340 +And I pretty much will do this +for all of my objects that + +1450 +01:07:36,340 --> 01:07:39,410 +come out of Core Data to +have these easy one-liners to + +1451 +01:07:39,410 --> 01:07:41,870 +create a FetchRequest for them, + +1452 +01:07:41,870 --> 01:07:44,540 +especially when you're +almost always wanting them + +1453 +01:07:44,540 --> 01:07:46,330 +sorted by the same thing, + +1454 +01:07:46,330 --> 01:07:48,830 +and Airline almost always +gonna be wanna be sorted by + +1455 +01:07:48,830 --> 01:07:49,840 +it's name, and Airport + +1456 +01:07:49,840 --> 01:07:51,930 +almost always gonna +wanna be sorted by it's + +1457 +01:07:51,930 --> 01:07:53,800 +location down here. + +1458 +01:07:53,800 --> 01:07:56,330 +Flight almost always gonna be wanna be + +1459 +01:07:56,330 --> 01:07:57,920 +sorted by arrival time. + +1460 +01:07:57,920 --> 01:08:00,170 +Now, if you wanted to specify +different SortDescriptors, + +1461 +01:08:00,170 --> 01:08:02,440 +of course you could get the +FetchRequest in here and then + +1462 +01:08:02,440 --> 01:08:05,900 +change the SortDescriptors, +it's just returning a var here, + +1463 +01:08:05,900 --> 01:08:07,073 +a FetchRequest var. + +1464 +01:08:08,630 --> 01:08:11,550 +So that makes our code +back here even simpler. + +1465 +01:08:11,550 --> 01:08:15,280 +We can actually just take this +predicate right here and say, + +1466 +01:08:15,280 --> 01:08:20,280 +let request equal a Flight.fetchRequest, + +1467 +01:08:21,380 --> 01:08:23,310 +where this is the predicate, + +1468 +01:08:25,180 --> 01:08:27,713 +so that, makes this a one-liner here. + +1469 +01:08:29,770 --> 01:08:34,630 +So now this flights var +is going to always be + +1470 +01:08:34,630 --> 01:08:35,820 +the result of this fetch. + +1471 +01:08:35,820 --> 01:08:38,480 +This is the amazing thing about this + +1472 +01:08:38,480 --> 01:08:40,260 +property wrapper right here. + +1473 +01:08:40,260 --> 01:08:43,510 +It's more than just letting +you specify the FetchRequest. + +1474 +01:08:43,510 --> 01:08:46,210 +It makes it so that this var + +1475 +01:08:46,210 --> 01:08:48,950 +always contains the result of this fetch. + +1476 +01:08:48,950 --> 01:08:51,530 +Even if objects are being +added or removing from the + +1477 +01:08:51,530 --> 01:08:56,300 +database that would match this, +it always is changing this. + +1478 +01:08:56,300 --> 01:08:58,140 +This is just constantly being updated, + +1479 +01:08:58,140 --> 01:09:02,190 +this fetch results to +reflect the latest version. + +1480 +01:09:02,190 --> 01:09:06,190 +And it's really one of the +really best integrations + +1481 +01:09:06,190 --> 01:09:10,060 +between SwiftUI and Core Data, +is that this ability to make + +1482 +01:09:10,060 --> 01:09:12,810 +these fetch results vars that are just + +1483 +01:09:12,810 --> 01:09:13,650 +always kept up to date. + +1484 +01:09:13,650 --> 01:09:14,823 +So for each down here, + +1485 +01:09:14,823 --> 01:09:19,016 +it's just always going to be +updating every time new Flights + +1486 +01:09:19,016 --> 01:09:20,060 +come in from FlightAware or whatever, + +1487 +01:09:20,060 --> 01:09:21,760 +it just automatically updates. + +1488 +01:09:22,710 --> 01:09:24,660 +So let's keep going here. + +1489 +01:09:24,660 --> 01:09:25,493 +What's the next error, + +1490 +01:09:25,493 --> 01:09:27,220 +we can just see it right here actually. + +1491 +01:09:27,220 --> 01:09:29,140 +FlightListEntry flight of flight, + +1492 +01:09:29,140 --> 01:09:32,190 +cannot convert FetchedResults +of Flight Elements. + +1493 +01:09:32,190 --> 01:09:34,832 +So the Element of a +FetchedResult of Flight, + +1494 +01:09:34,832 --> 01:09:38,310 +which will be AKA, a Flight, +to expect an argument, + +1495 +01:09:38,310 --> 01:09:41,550 +FAFlight, of course, +because a FlightListEntry, + +1496 +01:09:41,550 --> 01:09:45,100 +this thing down here, it +expects to get an FAFlight. + +1497 +01:09:45,100 --> 01:09:47,600 +'Cause this is the old world here, + +1498 +01:09:47,600 --> 01:09:49,150 +the pre-Core Data world. + +1499 +01:09:49,150 --> 01:09:50,140 +So let's fix this. + +1500 +01:09:50,140 --> 01:09:52,070 +This flight does not +want to be an FAFlight, + +1501 +01:09:52,070 --> 01:09:53,760 +it wants to be a Flight. + +1502 +01:09:53,760 --> 01:09:55,540 +And one huge advantage of that is + +1503 +01:09:55,540 --> 01:09:57,627 +that flight is an ObservableObject. + +1504 +01:09:57,627 --> 01:10:01,330 +So I'm gonna say @ObservedObject Flight. + +1505 +01:10:01,330 --> 01:10:03,800 +So if anything changes about +this Flight in the database, + +1506 +01:10:03,800 --> 01:10:05,280 +this View is gonna redraw. + +1507 +01:10:05,280 --> 01:10:08,280 +This is one of the huge +advantages of making this object- + +1508 +01:10:08,280 --> 01:10:10,440 +oriented, instead of +having this be a String, + +1509 +01:10:10,440 --> 01:10:12,490 +this is a String, there's no way to know, + +1510 +01:10:12,490 --> 01:10:14,410 +oh, that Flight got updated. + +1511 +01:10:14,410 --> 01:10:17,720 +And in FlightListEntry we +also have these other objects + +1512 +01:10:17,720 --> 01:10:20,970 +which are getting all the +Airports and all the Airlines. + +1513 +01:10:20,970 --> 01:10:24,690 +We don't really need +those anymore because it, + +1514 +01:10:24,690 --> 01:10:28,980 +when we get Airlines and Airports +nowadays, they're objects + +1515 +01:10:28,980 --> 01:10:31,480 +and we can get all the info +we want about them from those + +1516 +01:10:31,480 --> 01:10:34,730 +objects, so we don't need to +have these allAirlines flight + +1517 +01:10:34,730 --> 01:10:38,850 +code, friendly name business, +instead, I can just go here + +1518 +01:10:38,850 --> 01:10:43,293 +and say, flight.airline.friendlyName. + +1519 +01:10:45,000 --> 01:10:46,150 +And similarly down here, + +1520 +01:10:46,150 --> 01:10:49,000 +we don't need this allAirport +to look up the flight by its + +1521 +01:10:49,000 --> 01:10:50,990 +origin whatever, we can just say, + +1522 +01:10:50,990 --> 01:10:53,993 +flight.origin.friendlyName. + +1523 +01:10:54,890 --> 01:10:58,250 +So this is all much more +object-oriented and it makes the + +1524 +01:10:58,250 --> 01:11:01,590 +code a lot cleaner, like + +1525 +01:11:01,590 --> 01:11:04,500 +friendlyName, flight.number +and friendlyName + +1526 +01:11:04,500 --> 01:11:08,560 +down here in the "from" field, +less of looking up things in + +1527 +01:11:08,560 --> 01:11:11,363 +random lists of info +structs and all that stuff. + +1528 +01:11:13,230 --> 01:11:15,470 +We still have all these +things in FlightFetcher, okay, + +1529 +01:11:15,470 --> 01:11:16,760 +poor FlightFetcher. + +1530 +01:11:16,760 --> 01:11:19,730 +Let's go over to FlightFetcher +here from the last + +1531 +01:11:19,730 --> 01:11:22,580 +lecture and just comment +this whole thing out + +1532 +01:11:22,580 --> 01:11:27,110 +because we really don't +need FlightFetcher anymore. + +1533 +01:11:27,110 --> 01:11:30,510 +Because we're using now just our database. + +1534 +01:11:30,510 --> 01:11:35,360 +There we go, and oh, no more errors. + +1535 +01:11:35,360 --> 01:11:38,930 +We fixed everything, changed +our world to be entire object- + +1536 +01:11:38,930 --> 01:11:43,930 +oriented and pretty straightforward +to fix all the things. + +1537 +01:11:44,320 --> 01:11:48,570 +And in fact, some of this +code much more readable + +1538 +01:11:48,570 --> 01:11:49,960 +and understandable. + +1539 +01:11:49,960 --> 01:11:51,203 +Let's see if it works. + +1540 +01:11:54,580 --> 01:11:57,570 +And there it is, and it does not work. + +1541 +01:11:57,570 --> 01:11:58,403 +Why? + +1542 +01:11:58,403 --> 01:12:00,400 +It's just no information, + +1543 +01:12:00,400 --> 01:12:02,340 +but this is actually working perfectly. + +1544 +01:12:02,340 --> 01:12:05,370 +It's just that there's +no data in our database. + +1545 +01:12:05,370 --> 01:12:07,440 +So we are looking at an empty database. + +1546 +01:12:07,440 --> 01:12:10,200 +Here's all the Flights +in our empty database. + +1547 +01:12:10,200 --> 01:12:14,350 +So we clearly need some code +to load up this database + +1548 +01:12:14,350 --> 01:12:17,733 +with the Flights to the +destination airport. + +1549 +01:12:18,580 --> 01:12:21,950 +So let's do that, over +here, there's new data, + +1550 +01:12:21,950 --> 01:12:24,450 +here's where we create this SFO. + +1551 +01:12:24,450 --> 01:12:27,280 +Lets create a little +Airport function here called + +1552 +01:12:27,280 --> 01:12:30,310 +fetchIncomingFlights. + +1553 +01:12:30,310 --> 01:12:32,710 +This is just gonna go off to FlightAware, + +1554 +01:12:32,710 --> 01:12:35,240 +fetch all the flights they're +coming to this airport + +1555 +01:12:35,240 --> 01:12:37,470 +right now, and put them in the database. + +1556 +01:12:37,470 --> 01:12:39,820 +And then everything will +just work from there + +1557 +01:12:39,820 --> 01:12:41,680 +because the rest of our +code is just looking in the + +1558 +01:12:41,680 --> 01:12:45,160 +database, just waiting +for something to happen. + +1559 +01:12:45,160 --> 01:12:48,640 +This fetch right here, is +just sitting there waiting for + +1560 +01:12:48,640 --> 01:12:50,740 +this to start giving some results. + +1561 +01:12:50,740 --> 01:12:54,570 +And it's just gonna redraw +and automatically do it. + +1562 +01:12:54,570 --> 01:12:56,120 +So let's go to Airport here, + +1563 +01:12:56,120 --> 01:12:58,460 +and do this fetchIncomingFlights. + +1564 +01:12:58,460 --> 01:13:00,890 +Now the fetchIncomingFlights, +I also commented it out, + +1565 +01:13:00,890 --> 01:13:03,970 +it's mostly again this FlightAware stuff, + +1566 +01:13:03,970 --> 01:13:06,720 +but I do wanna focus on +this line right here. + +1567 +01:13:06,720 --> 01:13:10,490 +This context = managedObjectContext. + +1568 +01:13:10,490 --> 01:13:12,790 +You notice that when we +created this function + +1569 +01:13:12,790 --> 01:13:14,600 +fetchIncomingFlights, + +1570 +01:13:14,600 --> 01:13:17,880 +we didn't pass the context, +the database context + +1571 +01:13:17,880 --> 01:13:19,020 +as an argument. + +1572 +01:13:19,020 --> 01:13:21,960 +So you might wonder how are +we gonna create Flights, + +1573 +01:13:21,960 --> 01:13:23,310 +we're fetching incoming flights, + +1574 +01:13:23,310 --> 01:13:24,570 +how are we gonna create +them in the database + +1575 +01:13:24,570 --> 01:13:26,500 +if we don't have a context? + +1576 +01:13:26,500 --> 01:13:29,880 +Well, this method +fetchIncomingFlights is an instance + +1577 +01:13:29,880 --> 01:13:33,520 +method on an Airport, and it +turns out that all objects + +1578 +01:13:33,520 --> 01:13:36,170 +that come out of Core +Data, Airports, Airlines, + +1579 +01:13:36,170 --> 01:13:37,530 +Flights, any of them, + +1580 +01:13:37,530 --> 01:13:40,080 +they know the context they came out of. + +1581 +01:13:40,080 --> 01:13:42,350 +And we're just gonna +use that same context, + +1582 +01:13:42,350 --> 01:13:44,180 +to put our Flights in. + +1583 +01:13:44,180 --> 01:13:46,840 +So this line of code, if let +context = managedObjectContext, + +1584 +01:13:46,840 --> 01:13:51,640 +is just accessing a var in the Airport, + +1585 +01:13:51,640 --> 01:13:54,150 +which is, what is the +managedObjectContext, + +1586 +01:13:54,150 --> 01:13:55,870 +you came out of. + +1587 +01:13:55,870 --> 01:13:59,330 +And this is really important +to know because otherwise + +1588 +01:13:59,330 --> 01:14:02,190 +you're gonna be end up +passing context around all the + +1589 +01:14:02,190 --> 01:14:05,500 +time unnecessarily, when +you have an instance + +1590 +01:14:05,500 --> 01:14:08,170 +from the database in your hand, + +1591 +01:14:08,170 --> 01:14:11,040 +you can always get the context +from the database and add + +1592 +01:14:11,040 --> 01:14:14,373 +more objects or fetch +other objects using that. + +1593 +01:14:15,560 --> 01:14:19,160 +Here's the asynchronous closure +that's executed when the + +1594 +01:14:19,160 --> 01:14:20,670 +information comes back from FlightAware. + +1595 +01:14:20,670 --> 01:14:23,600 +So this is very similar +to what we had up here, + +1596 +01:14:23,600 --> 01:14:27,470 +when this AirportInfoRequest +fetched an airport, + +1597 +01:14:27,470 --> 01:14:29,740 +and here's where it came +back with the result. + +1598 +01:14:29,740 --> 01:14:32,090 +We have the exact same +thing going down here, + +1599 +01:14:32,090 --> 01:14:33,340 +where we have the result. + +1600 +01:14:34,360 --> 01:14:36,120 +So what am I gonna do when the information + +1601 +01:14:36,120 --> 01:14:37,500 +comes back from FlightAware? + +1602 +01:14:37,500 --> 01:14:39,627 +Well, this is an Array of FAFlight, + +1603 +01:14:39,627 --> 01:14:42,040 +you all remember FAFlight +over here as all the + +1604 +01:14:42,040 --> 01:14:44,430 +information that comes +back from FlightAware. + +1605 +01:14:44,430 --> 01:14:47,740 +So I'm going to go through +all those FAFlights + +1606 +01:14:47,740 --> 01:14:50,740 +with a for loop, for +faflight in those results. + +1607 +01:14:50,740 --> 01:14:54,080 +Now I'm gonna call a function in Flight + +1608 +01:14:54,080 --> 01:14:56,100 +that updates from an FAFlight. + +1609 +01:14:56,100 --> 01:14:59,530 +Again, just like I have +update from up here, + +1610 +01:14:59,530 --> 01:15:02,900 +that updates from AirportInfo in Airport, + +1611 +01:15:02,900 --> 01:15:07,110 +I'm gonna put this method +almost exactly the same method, + +1612 +01:15:07,110 --> 01:15:11,010 +but with all flight-oriented +stuff here into Flight. + +1613 +01:15:11,010 --> 01:15:12,060 +So let's go over and do that. + +1614 +01:15:12,060 --> 01:15:17,060 +Here's Flight, and you can +see it's doing the same thing, + +1615 +01:15:17,324 --> 01:15:21,800 +FetchRequest, looking things +up by ident all these things. + +1616 +01:15:21,800 --> 01:15:26,800 +This again, could be, let +request = fetchRequest, + +1617 +01:15:29,440 --> 01:15:32,810 +with this predicate, so we can make that + +1618 +01:15:32,810 --> 01:15:34,620 +a one liner right there. + +1619 +01:15:34,620 --> 01:15:36,870 +And so we're searching for +this Flight by whatever it's + +1620 +01:15:36,870 --> 01:15:39,580 +ident is in the FAFlight. + +1621 +01:15:39,580 --> 01:15:42,077 +That's what the search predicate is. + +1622 +01:15:42,077 --> 01:15:44,190 +And we're doing exact same +thing we did in Airport, + +1623 +01:15:44,190 --> 01:15:46,090 +looking to see if we found a result, + +1624 +01:15:46,090 --> 01:15:47,880 +if we find it, in this case though, + +1625 +01:15:47,880 --> 01:15:49,550 +Flights are a little +different because they get + +1626 +01:15:49,550 --> 01:15:50,860 +updated over time. + +1627 +01:15:50,860 --> 01:15:53,630 +So if we find it or not, +we're going to update it with + +1628 +01:15:53,630 --> 01:15:55,823 +whatever information came back. + +1629 +01:15:56,810 --> 01:15:59,990 +And this is all just stuff we saw before. + +1630 +01:15:59,990 --> 01:16:02,280 +A couple of interesting +things going on in here + +1631 +01:16:02,280 --> 01:16:05,710 +is here I'm setting +some relationship vars. + +1632 +01:16:05,710 --> 01:16:08,360 +So here's my origin and +destination airport. + +1633 +01:16:08,360 --> 01:16:09,193 +Look what I'm doing, + +1634 +01:16:09,193 --> 01:16:13,330 +I'm creating an Airport +with that origin var + +1635 +01:16:13,330 --> 01:16:15,730 +'cause an FAFlight origin is a String. + +1636 +01:16:15,730 --> 01:16:20,338 +So I'm looking that ICAO +up in our current context, + +1637 +01:16:20,338 --> 01:16:23,360 +the context that we've +passed into us here, + +1638 +01:16:23,360 --> 01:16:24,420 +and creating an Airport. + +1639 +01:16:24,420 --> 01:16:26,470 +Same thing here for the +destination Airport. + +1640 +01:16:26,470 --> 01:16:30,150 +And after the same thing for +airline, because in FAFlight, + +1641 +01:16:30,150 --> 01:16:31,520 +airlineCode is a String. + +1642 +01:16:31,520 --> 01:16:33,050 +So I need to create an Airline. + +1643 +01:16:33,050 --> 01:16:36,610 +So in Airline we need a +little thing that looks it up, + +1644 +01:16:36,610 --> 01:16:38,690 +and finds it, return to +it, if not, it creates it + +1645 +01:16:38,690 --> 01:16:39,740 +just like we had an Airport. + +1646 +01:16:39,740 --> 01:16:41,363 +So let's go do that in Airline, + +1647 +01:16:43,450 --> 01:16:47,143 +and this with code, looks +very similar to the Airport. + +1648 +01:16:47,143 --> 01:16:49,530 +It's just that these are +all different down here. + +1649 +01:16:49,530 --> 01:16:51,870 +We're still doing the +objectWillChange though here. + +1650 +01:16:51,870 --> 01:16:53,390 +And same thing with the Flights. + +1651 +01:16:53,390 --> 01:16:56,160 +So if this airline +information comes available + +1652 +01:16:56,160 --> 01:16:59,110 +from FlightAware, we're +going to do objectWillChange + +1653 +01:16:59,110 --> 01:17:00,233 +on all those things. + +1654 +01:17:01,540 --> 01:17:03,890 +One of the things I +wanted to show you is the, + +1655 +01:17:03,890 --> 01:17:05,360 +when I'm loading up these Flights, + +1656 +01:17:05,360 --> 01:17:07,890 +I'm going to show you what it +looks like to try and catch + +1657 +01:17:07,890 --> 01:17:10,200 +the error from context save. + +1658 +01:17:10,200 --> 01:17:12,420 +Just because we haven't +really been doing this, + +1659 +01:17:12,420 --> 01:17:14,620 +we've been doing try? everywhere, + +1660 +01:17:14,620 --> 01:17:18,330 +but if you just put a do catch +around the thing you wanna + +1661 +01:17:18,330 --> 01:17:21,360 +try, this throws an error and +this will catch that error. + +1662 +01:17:21,360 --> 01:17:24,170 +And then you can do things +like print out that error's + +1663 +01:17:24,170 --> 01:17:26,270 +localizedDescription or +something right here, + +1664 +01:17:26,270 --> 01:17:29,500 +and here we can handle the +error where we try to save the + +1665 +01:17:29,500 --> 01:17:31,430 +context and we couldn't. + +1666 +01:17:31,430 --> 01:17:34,810 +If your context save fails +something pretty bad going on, + +1667 +01:17:34,810 --> 01:17:37,580 +maybe your disk is full or, you know, + +1668 +01:17:37,580 --> 01:17:40,754 +something pretty heinous +is happening here. + +1669 +01:17:40,754 --> 01:17:43,960 +So there's not usually much +you can do to handle failure to + +1670 +01:17:43,960 --> 01:17:47,079 +say, maybe try to save again +in a few seconds or something, + +1671 +01:17:47,079 --> 01:17:49,943 +but it's a tough one to recover from. + +1672 +01:17:51,270 --> 01:17:53,180 +So that's all that's happening +here in fetch incoming + +1673 +01:17:53,180 --> 01:17:57,010 +flights, we are just loading +up the database with things + +1674 +01:17:57,010 --> 01:17:59,220 +that are coming in from FlightAware. + +1675 +01:17:59,220 --> 01:18:00,920 +That's all we're doing repeatedly. + +1676 +01:18:02,730 --> 01:18:04,033 +See if that works. + +1677 +01:18:06,510 --> 01:18:10,620 +Well, look at that, loading +it up in the database. + +1678 +01:18:10,620 --> 01:18:13,760 +And wow, now our data is +showing a lot of Flights + +1679 +01:18:13,760 --> 01:18:14,760 +and they're still coming in. + +1680 +01:18:14,760 --> 01:18:16,750 +It's loading more and more flights. + +1681 +01:18:16,750 --> 01:18:19,950 +And what we're looking at +here though, is the database. + +1682 +01:18:19,950 --> 01:18:21,820 +This is purely looking at the database. + +1683 +01:18:21,820 --> 01:18:23,410 +All this flight fetching that's happening, + +1684 +01:18:23,410 --> 01:18:28,410 +happening asynchronously to +what's going on here in the UI. + +1685 +01:18:28,730 --> 01:18:31,060 +Now glancing at my code there on the left, + +1686 +01:18:31,060 --> 01:18:33,140 +I can actually see, we forgot something, + +1687 +01:18:33,140 --> 01:18:36,990 +which is we don't have our +Flight do its objectWillChange, + +1688 +01:18:36,990 --> 01:18:39,350 +even though we're possibly +doing a big update + +1689 +01:18:39,350 --> 01:18:40,560 +to a Flight there. + +1690 +01:18:40,560 --> 01:18:43,270 +And then also I see a +problem here at the top + +1691 +01:18:43,270 --> 01:18:45,789 +where it's not saying flights to KSFO, + +1692 +01:18:45,789 --> 01:18:49,340 +it's saying flights to +airport 0X, whatever. + +1693 +01:18:49,340 --> 01:18:52,890 +And that's happening because +we're printing out an Airport + +1694 +01:18:52,890 --> 01:18:57,040 +object there, instead of +printing out it's ICAO code. + +1695 +01:18:57,040 --> 01:18:59,390 +So let's fix both of those problems, + +1696 +01:18:59,390 --> 01:19:01,170 +starting with right here, + +1697 +01:19:01,170 --> 01:19:05,340 +we forgot to say that we want our Flight + +1698 +01:19:05,340 --> 01:19:10,000 +that we just created, to have +its objectWillChange.send() + +1699 +01:19:10,000 --> 01:19:12,960 +sent because we just changed +a lot of fields and we wanna + +1700 +01:19:12,960 --> 01:19:17,600 +make sure that our UI will +update with whatever that is. + +1701 +01:19:17,600 --> 01:19:21,073 +And then we can fix that title +problem with the Airport, + +1702 +01:19:22,070 --> 01:19:26,600 +which we're doing over here, +by saying backslash open + +1703 +01:19:26,600 --> 01:19:29,640 +parentheses, closed +parentheses, with the object. + +1704 +01:19:29,640 --> 01:19:31,260 +We don't really want the object here. + +1705 +01:19:31,260 --> 01:19:34,213 +We want this destination's ICAO. + +1706 +01:19:36,950 --> 01:19:37,783 +So let's do that. + +1707 +01:19:37,783 --> 01:19:38,883 +Fix that problem. + +1708 +01:19:43,260 --> 01:19:44,093 +There it is. + +1709 +01:19:44,093 --> 01:19:44,926 +There's it's ICAO. + +1710 +01:19:46,940 --> 01:19:47,773 +All right. + +1711 +01:19:47,773 --> 01:19:50,360 +The last piece we have to do +is fix our filter right here + +1712 +01:19:50,360 --> 01:19:52,120 +because our filter, lemme show you + +1713 +01:19:52,120 --> 01:19:53,310 +what they'll do right now. + +1714 +01:19:53,310 --> 01:19:55,680 +It's not gonna work because this filter + +1715 +01:19:55,680 --> 01:19:57,550 +is built to work with Strings. + +1716 +01:19:57,550 --> 01:20:00,060 +It's supposed to be +picking Strings over here, + +1717 +01:20:00,060 --> 01:20:01,350 +this FilterFFlights. + +1718 +01:20:01,350 --> 01:20:05,000 +And you know, we changed all +of our Flights to be objects. + +1719 +01:20:05,000 --> 01:20:07,020 +So this needs the object-oriented + +1720 +01:20:07,020 --> 01:20:09,070 +treatment as well over here. + +1721 +01:20:09,070 --> 01:20:11,880 +Now, when we're letting people +choose Airports and Airlines, + +1722 +01:20:11,880 --> 01:20:14,740 +we actually do need all the +Airports and all the Airlines + +1723 +01:20:14,740 --> 01:20:15,790 +that are available, + +1724 +01:20:15,790 --> 01:20:20,253 +but we're not gonna do it +again with these old ViewModel + +1725 +01:20:20,253 --> 01:20:23,160 +airports all and airlines all instead, + +1726 +01:20:23,160 --> 01:20:24,727 +we're gonna do FetchRequests here, + +1727 +01:20:24,727 --> 01:20:26,850 +and these are gonna be +FetchRequests for Airports and + +1728 +01:20:26,850 --> 01:20:29,400 +Airlines, I'm gonna do a FetchRequest, + +1729 +01:20:29,400 --> 01:20:34,340 +and I'm gonna have the +FetchRequest here be hardwired in + +1730 +01:20:34,340 --> 01:20:39,340 +here, it's gonna be airport.fetchRequest, + +1731 +01:20:39,550 --> 01:20:44,550 +where the predicate is essentially all, + +1732 +01:20:45,750 --> 01:20:47,960 +I need all my Airports. + +1733 +01:20:47,960 --> 01:20:51,510 +I'm gonna use this FetchRequest +to get a little var + +1734 +01:20:51,510 --> 01:20:55,610 +airports here, which is +gonna be all of my Airports. + +1735 +01:20:55,610 --> 01:20:59,640 +This is the same FetchedResults +thing that I was doing over + +1736 +01:20:59,640 --> 01:21:02,300 +here, but over here, I was doing +the FetchedResults based on + +1737 +01:21:02,300 --> 01:21:05,401 +looking up the destination +Airport, in this case, + +1738 +01:21:05,401 --> 01:21:08,310 +I want all of my Airports. + +1739 +01:21:08,310 --> 01:21:10,270 +So what kind of predicate means all, + +1740 +01:21:10,270 --> 01:21:11,510 +well, there's a great predicate for that + +1741 +01:21:11,510 --> 01:21:13,473 +called TRUEPREDICATE. + +1742 +01:21:13,473 --> 01:21:15,420 +That just basically means this evaluates + +1743 +01:21:15,420 --> 01:21:17,300 +to true at all times. + +1744 +01:21:17,300 --> 01:21:18,910 +That's so common to use. + +1745 +01:21:18,910 --> 01:21:21,000 +I actually created a little extension, + +1746 +01:21:21,000 --> 01:21:25,140 +called, to NSPredicate, +called, all which does that, + +1747 +01:21:25,140 --> 01:21:27,742 +and none which does the false. + +1748 +01:21:27,742 --> 01:21:30,200 +Seems like I'm always doing a predicate, + +1749 +01:21:30,200 --> 01:21:32,080 +TRUEPREDICATE somewhere in my app. + +1750 +01:21:32,080 --> 01:21:33,840 +So I'm gonna change that to all. + +1751 +01:21:33,840 --> 01:21:36,270 +That's it, that's going +to fetch all the Airports. + +1752 +01:21:36,270 --> 01:21:39,600 +This airports var will +always be all the Airports, + +1753 +01:21:39,600 --> 01:21:42,930 +even if airports are added, +this automatically updates so + +1754 +01:21:42,930 --> 01:21:46,770 +that this FetchedResults thing +that we're doing ForEach-ing + +1755 +01:21:46,770 --> 01:21:49,260 +inside of our Pickers down here, + +1756 +01:21:49,260 --> 01:21:50,710 +will always be updated. + +1757 +01:21:50,710 --> 01:21:54,960 +And same thing we'll do for our Airline. + +1758 +01:21:54,960 --> 01:21:57,130 +Now we have all our Airports +and all our Airlines, + +1759 +01:21:57,130 --> 01:22:00,460 +and we're gonna use that down +here, inside of our Pickers, + +1760 +01:22:00,460 --> 01:22:05,140 +because our Pickers are +currently picking these codes, + +1761 +01:22:05,140 --> 01:22:08,130 +but we want them to +actually pick the objects. + +1762 +01:22:08,130 --> 01:22:12,030 +We want them to pick +Airport and Airline objects. + +1763 +01:22:12,030 --> 01:22:14,560 +So instead of being +all airport codes here, + +1764 +01:22:14,560 --> 01:22:17,453 +this is just going to be our Airports, + +1765 +01:22:18,410 --> 01:22:20,560 +and I'm gonna sort them, sorted. + +1766 +01:22:20,560 --> 01:22:23,110 +Our Airports if you remember, +when I showed you Airport + +1767 +01:22:23,110 --> 01:22:26,370 +over here, I made it so +that it implemented this + +1768 +01:22:28,180 --> 01:22:29,853 +Comparable protocol. + +1769 +01:22:30,760 --> 01:22:34,600 +So this Comparable protocol is +a little less than function. + +1770 +01:22:34,600 --> 01:22:36,370 +And if you implement Comparable, + +1771 +01:22:36,370 --> 01:22:40,110 +then you can have Collections +like Airports or Arrays of + +1772 +01:22:40,110 --> 01:22:43,630 +things, sort themselves by saying sorted. + +1773 +01:22:43,630 --> 01:22:45,230 +Now this is object-oriented. + +1774 +01:22:45,230 --> 01:22:47,620 +So we don't wanna be, need to +be looking this up like this. + +1775 +01:22:47,620 --> 01:22:52,250 +We can just say, instead, here +our Airport's friendlyName + +1776 +01:22:52,250 --> 01:22:55,490 +to get the Airport, and +this never returns nil, + +1777 +01:22:55,490 --> 01:22:58,540 +so we don't need to +optionally default that. + +1778 +01:22:58,540 --> 01:23:02,300 +Good, so this code actually +cleaned up quite nicely. + +1779 +01:23:02,300 --> 01:23:04,000 +And what about our origin? + +1780 +01:23:04,000 --> 01:23:05,890 +Similar, except for that, of course, + +1781 +01:23:05,890 --> 01:23:07,720 +this is no longer a String. + +1782 +01:23:07,720 --> 01:23:11,950 +So we don't want the Optional +nil for Optional String. + +1783 +01:23:11,950 --> 01:23:15,650 +We want Airport Optional, + +1784 +01:23:15,650 --> 01:23:17,870 +right there so that's +been nil for Airport. + +1785 +01:23:17,870 --> 01:23:19,500 +And again, not allAirports.codes, + +1786 +01:23:19,500 --> 01:23:21,753 +we want Airports.sorted(). + +1787 +01:23:23,270 --> 01:23:26,110 +And again, the Airport is already + +1788 +01:23:27,410 --> 01:23:30,660 +got its own friendlyName in an +object-oriented kind of way. + +1789 +01:23:30,660 --> 01:23:33,840 +Still want the ?? Any, because, + +1790 +01:23:33,840 --> 01:23:37,830 +this airport is allowed to +be nil and it's not Optional + +1791 +01:23:37,830 --> 01:23:39,703 +String, it's Optional Airport. + +1792 +01:23:42,560 --> 01:23:45,670 +So now this is picking Optional Airports, + +1793 +01:23:45,670 --> 01:23:47,720 +just like this is picking Airport. + +1794 +01:23:47,720 --> 01:23:50,230 +And this is Airline down here. + +1795 +01:23:50,230 --> 01:23:52,730 +This is probably more similar to this, + +1796 +01:23:52,730 --> 01:23:54,230 +than it is to this other one. + +1797 +01:23:54,230 --> 01:23:56,770 +So if I copy and paste right here, + +1798 +01:23:56,770 --> 01:23:59,190 +change this to be our Airline. + +1799 +01:23:59,190 --> 01:24:03,040 +And I'm gonna search and +replace this airport, + +1800 +01:24:03,040 --> 01:24:04,333 +with our airline + +1801 +01:24:06,043 --> 01:24:09,180 +We've converted these now to use objects + +1802 +01:24:09,180 --> 01:24:11,830 +instead of their Strings. + +1803 +01:24:11,830 --> 01:24:14,390 +Otherwise this code can stay the same. + +1804 +01:24:14,390 --> 01:24:16,420 +One last thing that I wanna do is, + +1805 +01:24:16,420 --> 01:24:18,480 +when the done button is pressed, + +1806 +01:24:18,480 --> 01:24:20,550 +if you've changed your destination, + +1807 +01:24:20,550 --> 01:24:24,010 +I wanna do this, fetchIncomingFlights. + +1808 +01:24:24,010 --> 01:24:27,280 +If you change from looking at SFO, + +1809 +01:24:27,280 --> 01:24:29,580 +to looking at Dallas Fort worth, + +1810 +01:24:29,580 --> 01:24:32,950 +I want to fetch those incoming flights. + +1811 +01:24:32,950 --> 01:24:34,110 +So I only wanna do it though, + +1812 +01:24:34,110 --> 01:24:36,800 +when you actually change your destination. + +1813 +01:24:36,800 --> 01:24:41,800 +So I'm gonna say, if my draft's +destination does not equal + +1814 +01:24:42,890 --> 01:24:47,890 +my flightSearch +destination, then self.draft + +1815 +01:24:49,750 --> 01:24:53,263 +destination fetchIncomingFlights. + +1816 +01:24:55,558 --> 01:24:56,540 +Lets take a look. + +1817 +01:24:56,540 --> 01:24:57,593 +See if this works. + +1818 +01:25:00,367 --> 01:25:01,342 +All right, here we go. + +1819 +01:25:01,342 --> 01:25:02,192 +Let's try filter. + +1820 +01:25:03,130 --> 01:25:06,960 +Oh no, it crashed, it +crashes, we hate crashes. + +1821 +01:25:06,960 --> 01:25:08,410 +What is going on? + +1822 +01:25:08,410 --> 01:25:10,713 +Let's look at our console down here. + +1823 +01:25:11,810 --> 01:25:15,110 +This is a very, very important error + +1824 +01:25:15,110 --> 01:25:16,550 +when you're working with Core Data, + +1825 +01:25:16,550 --> 01:25:19,530 +to understand what this is. + +1826 +01:25:19,530 --> 01:25:23,200 +It says, context in your +Environment, is not connected to + +1827 +01:25:23,200 --> 01:25:25,640 +the persistent store coordinator. + +1828 +01:25:25,640 --> 01:25:29,390 +If you remember back over +here in SceneDelegate, + +1829 +01:25:29,390 --> 01:25:33,570 +we created this thing context +out of our persistent store, + +1830 +01:25:33,570 --> 01:25:35,000 +this persistent container. + +1831 +01:25:35,000 --> 01:25:37,220 +This is our View into the database, + +1832 +01:25:37,220 --> 01:25:40,710 +and we had to pass it +in to our Enroute View, + +1833 +01:25:40,710 --> 01:25:42,490 +via this environment. + +1834 +01:25:42,490 --> 01:25:47,280 +But we then, from our honorary View, + +1835 +01:25:47,280 --> 01:25:51,500 +put up a sheet with +FilterFlights and sheets + +1836 +01:25:51,500 --> 01:25:53,070 +get their own environments. + +1837 +01:25:53,070 --> 01:25:55,900 +So we have to do the same thing here, + +1838 +01:25:55,900 --> 01:26:00,440 +and pass into this +environment, this context. + +1839 +01:26:00,440 --> 01:26:03,500 +Now the only problem +here is, what is context? + +1840 +01:26:03,500 --> 01:26:06,480 +It says unresolved +identifier, where is context? + +1841 +01:26:06,480 --> 01:26:09,360 +Well, we're gonna have +to get our context here, + +1842 +01:26:09,360 --> 01:26:10,760 +so that we can pass it here. + +1843 +01:26:13,775 --> 01:26:17,430 +We're gonna get that here, +from our environment, + +1844 +01:26:17,430 --> 01:26:22,430 +a managedObjectContext, which +is a var we'll call context. + +1845 +01:26:24,670 --> 01:26:26,687 +So here, I'm grabbing +this context out of here. + +1846 +01:26:26,687 --> 01:26:30,330 +I'm out of my Environment, +and I'm passing it along + +1847 +01:26:30,330 --> 01:26:32,230 +to this sheet's Environment. + +1848 +01:26:32,230 --> 01:26:34,330 +So this guy has Environment. + +1849 +01:26:34,330 --> 01:26:37,460 +So this is a common +error to get down here. + +1850 +01:26:37,460 --> 01:26:41,220 +And so, really make sure +that you burn in your brain, + +1851 +01:26:41,220 --> 01:26:42,380 +what this means. + +1852 +01:26:42,380 --> 01:26:46,410 +It just means you needed to +pass into a sheet or something. + +1853 +01:26:46,410 --> 01:26:49,140 +Anything that puts up this +modal popover whatever, + +1854 +01:26:49,140 --> 01:26:51,077 +pass this context in there. + +1855 +01:26:51,077 --> 01:26:55,520 +And the reason for that is, +things like FetchRequest + +1856 +01:26:55,520 --> 01:26:57,200 +depend on that context. + +1857 +01:26:57,200 --> 01:26:59,117 +How else are they gonna know +where to get these Airports + +1858 +01:26:59,117 --> 01:27:00,420 +and Airlines from? + +1859 +01:27:00,420 --> 01:27:03,313 +They need the context to +be in their Environment. + +1860 +01:27:06,700 --> 01:27:07,533 +Oh yes. + +1861 +01:27:07,533 --> 01:27:09,280 +So, we gotta put a self dot over there, + +1862 +01:27:09,280 --> 01:27:10,937 +now we can do it. + +1863 +01:27:13,549 --> 01:27:15,450 +Okay, here we go, let's try it filter. + +1864 +01:27:15,450 --> 01:27:18,490 +Oh, that looks better, +destination San Francisco. + +1865 +01:27:18,490 --> 01:27:21,542 +Wow, there's are all over the Denver. + +1866 +01:27:21,542 --> 01:27:24,201 +Now that didn't fetch, that's good. + +1867 +01:27:24,201 --> 01:27:26,170 +I haven't said done here, + +1868 +01:27:26,170 --> 01:27:28,096 +so it didn't go off and do a fetch there. + +1869 +01:27:28,096 --> 01:27:31,880 +Origin yeah, looking good, airline yeah, + +1870 +01:27:31,880 --> 01:27:34,056 +I'm gonna say United. + +1871 +01:27:34,056 --> 01:27:34,889 +What about that? + +1872 +01:27:34,889 --> 01:27:36,090 +Oh, airline not working. + +1873 +01:27:36,090 --> 01:27:38,420 +See that airline, not working. + +1874 +01:27:38,420 --> 01:27:40,700 +So let's go back and take +a look at airline tell you, + +1875 +01:27:40,700 --> 01:27:43,800 +what we did wrong there +probably a copy and paste error + +1876 +01:27:43,800 --> 01:27:45,053 +that we made down there. + +1877 +01:27:45,890 --> 01:27:48,283 +So that's in FilterFlights. + +1878 +01:27:49,320 --> 01:27:52,550 +So airlines see, oh, +look at this draft.origin + +1879 +01:27:52,550 --> 01:27:57,263 +for the Airline, no, +this is draft.airline. + +1880 +01:27:58,290 --> 01:27:59,123 +Try that. + +1881 +01:28:02,200 --> 01:28:04,040 +Alright, so that's it for, that's good. + +1882 +01:28:04,040 --> 01:28:07,050 +Now airline, oh, looking +much better already, + +1883 +01:28:07,050 --> 01:28:11,570 +United, lets go to Boston, +and I'm gonna hit done, + +1884 +01:28:11,570 --> 01:28:14,370 +and hopefully then it +will do another fetch. + +1885 +01:28:14,370 --> 01:28:16,190 +Whoop, there it is Boston. + +1886 +01:28:16,190 --> 01:28:18,630 +And again, we're looking +in the database here, + +1887 +01:28:18,630 --> 01:28:20,560 +and if we go back to San Francisco, + +1888 +01:28:20,560 --> 01:28:22,830 +you'll notice something interesting here. + +1889 +01:28:22,830 --> 01:28:24,070 +Pay close attention. + +1890 +01:28:24,070 --> 01:28:25,720 +Well, a lot of airports in there. + +1891 +01:28:26,820 --> 01:28:28,810 +I think it's just go, here it is. + +1892 +01:28:28,810 --> 01:28:31,500 +Watch when I hit done here, + +1893 +01:28:31,500 --> 01:28:33,750 +whoop, how quickly SFO load it up, + +1894 +01:28:33,750 --> 01:28:37,326 +because it's showing me +stuff that's in the database, + +1895 +01:28:37,326 --> 01:28:39,380 +and it's continuing to update them, + +1896 +01:28:39,380 --> 01:28:42,810 +but we're getting this instant +response from the database, + +1897 +01:28:42,810 --> 01:28:45,350 +which is another great kind +of side effect of moving this + +1898 +01:28:45,350 --> 01:28:46,623 +stuff in the database. + +1899 +01:28:48,680 --> 01:28:53,120 +Now it's not quite right +yet, because I changed this + +1900 +01:28:53,120 --> 01:28:56,320 +if you remember, to have +United as my airline, + +1901 +01:28:56,320 --> 01:29:00,600 +but this is giving me other +airlines besides United, right? + +1902 +01:29:00,600 --> 01:29:04,150 +Well that's because back +here in our FlightEnroute, + +1903 +01:29:04,150 --> 01:29:06,270 +when we were looking up our Flights, + +1904 +01:29:06,270 --> 01:29:09,543 +our predicate here is +just the destination only. + +1905 +01:29:10,570 --> 01:29:15,013 +This is not looking at the +airline and things like that. + +1906 +01:29:15,013 --> 01:29:16,720 +It's the destination only. + +1907 +01:29:16,720 --> 01:29:21,560 +So we need this predicate right +here, to be some predicate, + +1908 +01:29:21,560 --> 01:29:26,560 +say that predicate equal, date +is based on this FlightSearch + +1909 +01:29:27,040 --> 01:29:30,350 +and all the things, not +just the destination. + +1910 +01:29:30,350 --> 01:29:34,080 +So I put a little extension +down here to FlightSearch + +1911 +01:29:34,080 --> 01:29:35,143 +to do that. + +1912 +01:29:36,260 --> 01:29:38,170 +And let's just move it all the way + +1913 +01:29:38,170 --> 01:29:40,910 +up to the top of the file here. + +1914 +01:29:40,910 --> 01:29:44,210 +And this FlightSearch extension +that I added is to add a + +1915 +01:29:44,210 --> 01:29:45,880 +var called predicate. + +1916 +01:29:45,880 --> 01:29:48,150 +That just is our implied search, right? + +1917 +01:29:48,150 --> 01:29:49,740 +So it's just looking at all these things, + +1918 +01:29:49,740 --> 01:29:53,340 +and building up an NSPredicate object, + +1919 +01:29:53,340 --> 01:29:56,960 +using more and more stuff in its format, + +1920 +01:29:56,960 --> 01:29:58,890 +you see its format is destination. + +1921 +01:29:58,890 --> 01:30:01,893 +Then if there's an +origin, I add, and origin. + +1922 +01:30:03,090 --> 01:30:06,130 +If there's an airline, I add, and airline. + +1923 +01:30:06,130 --> 01:30:08,470 +And along the way, I have this args, + +1924 +01:30:08,470 --> 01:30:10,543 +which is an Array of NSManagedObject. + +1925 +01:30:11,890 --> 01:30:14,470 +Now, what is NSManagedObject? + +1926 +01:30:14,470 --> 01:30:19,470 +This is the superclass of +Flight, Airport and Airline. + +1927 +01:30:19,550 --> 01:30:22,910 +So if I wanna create an Array +that could have Flights in it, + +1928 +01:30:22,910 --> 01:30:25,460 +or Airports or Airlines, + +1929 +01:30:25,460 --> 01:30:28,980 +then I can make an Array +of NSManagedObject, + +1930 +01:30:28,980 --> 01:30:31,850 +since those all inherit +from there, this works. + +1931 +01:30:31,850 --> 01:30:34,100 +So this is the args, so +it's getting the destination + +1932 +01:30:34,100 --> 01:30:36,450 +in there to start, and +then if there is an origin + +1933 +01:30:36,450 --> 01:30:38,957 +it puts that in there, if there's +an Airline it puts that in + +1934 +01:30:38,957 --> 01:30:41,600 +there, and then we're just +saying NSPredicate format, + +1935 +01:30:41,600 --> 01:30:44,710 +this String we built up, +and the argument Array, + +1936 +01:30:44,710 --> 01:30:47,969 +is these args that I build up. + +1937 +01:30:47,969 --> 01:30:51,310 +This is how you kind of, can +kind of build a programmatic + +1938 +01:30:51,310 --> 01:30:53,820 +predicate that's based on decision-making, + +1939 +01:30:53,820 --> 01:30:55,473 +like what's in this struct. + +1940 +01:30:56,660 --> 01:30:58,830 +So I'm just gonna use this +predicate var down here, + +1941 +01:30:58,830 --> 01:31:02,510 +and say, flightSearch.predicate. + +1942 +01:31:02,510 --> 01:31:04,780 +Give me a predicate for this FlightSearch. + +1943 +01:31:04,780 --> 01:31:06,663 +And I'm gonna use that to search. + +1944 +01:31:07,800 --> 01:31:09,473 +We don't need that, not anymore. + +1945 +01:31:11,490 --> 01:31:13,030 +It's simpler, in fact, this is so simple, + +1946 +01:31:13,030 --> 01:31:15,713 +we could just put this +right in here like that. + +1947 +01:31:18,828 --> 01:31:19,853 +See if that works. + +1948 +01:31:22,820 --> 01:31:26,200 +Notice SFO instantly showing +us data in the database, + +1949 +01:31:26,200 --> 01:31:29,390 +the data that's valid anyway, to show us, + +1950 +01:31:29,390 --> 01:31:32,550 +and let's go airport here, +and go down to United, + +1951 +01:31:32,550 --> 01:31:33,880 +that's a hub for San Francisco. + +1952 +01:31:33,880 --> 01:31:35,490 +So there should be flights and churn up. + +1953 +01:31:35,490 --> 01:31:39,660 +There it is, that's working +and we could go origin. + +1954 +01:31:39,660 --> 01:31:41,370 +What was in the origins there? + +1955 +01:31:41,370 --> 01:31:43,390 +Boston, we can find Boston. + +1956 +01:31:43,390 --> 01:31:46,810 +We know that Boston is there, +Logan airport in Boston. + +1957 +01:31:46,810 --> 01:31:50,260 +So now we're gonna look +both Boston and United, + +1958 +01:31:50,260 --> 01:31:51,460 +found that, that's good. + +1959 +01:31:53,540 --> 01:31:56,030 +And, we should go back to +saying, show us any plane + +1960 +01:31:56,030 --> 01:31:58,280 +coming from Boston, on this one flight, + +1961 +01:31:58,280 --> 01:32:01,800 +lemme go back here and +say, shows any airlines, + +1962 +01:32:01,800 --> 01:32:03,593 +any place, here they are. + +1963 +01:32:05,770 --> 01:32:06,900 +Alright. + +1964 +01:32:06,900 --> 01:32:09,620 +So that's a lot of code in that demo. + +1965 +01:32:09,620 --> 01:32:11,460 +Lot to show you there, + +1966 +01:32:11,460 --> 01:32:16,340 +but hopefully you've gotten a +good feel for how we build our + +1967 +01:32:16,340 --> 01:32:18,920 +UI out of data in the database, + +1968 +01:32:18,920 --> 01:32:23,705 +especially the way we do +these FetchRequests that are + +1969 +01:32:23,705 --> 01:32:26,850 +recurring results, they're +just constantly kept up to date + +1970 +01:32:26,850 --> 01:32:28,700 +as we change things. + +1971 +01:32:28,700 --> 01:32:31,760 +And that makes it to +the rest of your code. + +1972 +01:32:31,760 --> 01:32:34,720 +Doesn't have to have many +if thens, and things change, + +1973 +01:32:34,720 --> 01:32:36,090 +and this, that, and the other thing, + +1974 +01:32:36,090 --> 01:32:37,050 +it just finds them. + +1975 +01:32:37,050 --> 01:32:38,500 +And notice that in Core Data, we're + +1976 +01:32:38,500 --> 01:32:42,130 +mostly using these FetchedResults +to have things change. + +1977 +01:32:42,130 --> 01:32:45,890 +Even though we can also use +ObservedObjects on individual + +1978 +01:32:45,890 --> 01:32:48,370 +Flights, Airlines, right, and +we're using it here if this + +1979 +01:32:48,370 --> 01:32:51,040 +Flight did change, since we did the + +1980 +01:32:51,040 --> 01:32:53,290 +objectWillChange.send() on there. + +1981 +01:32:53,290 --> 01:32:54,123 +It would update, + +1982 +01:32:54,123 --> 01:32:58,980 +but that's more rare even than +doing these FetchedResults, + +1983 +01:32:58,980 --> 01:33:01,760 +really FetchedResults and +having this dynamically always + +1984 +01:33:01,760 --> 01:33:02,810 +show you what's in the database, + +1985 +01:33:02,810 --> 01:33:05,590 +that's really the heart of the SwiftUI + +1986 +01:33:05,590 --> 01:33:07,493 +to Core Data integration. + +1987 +01:33:09,100 --> 01:33:09,933 +All right. + +1988 +01:33:09,933 --> 01:33:11,640 +I will really love to see some of you + +1989 +01:33:11,640 --> 01:33:13,690 +do this in your final project. + +1990 +01:33:13,690 --> 01:33:15,840 +There's certainly a lot of +need in a lot of different + +1991 +01:33:15,840 --> 01:33:18,990 +project ideas, for permanent +storage resistant storage. + +1992 +01:33:18,990 --> 01:33:23,460 +And this is a lot more powerful +than doing UserDefaults. + +1993 +01:33:23,460 --> 01:33:26,303 +So I'm hoping that you +guys will tackle this. + +1994 +01:33:27,260 --> 01:33:30,513 +- [Animaker Voice] For more, +please visit us @stanford.edu. diff --git a/subtitles/en/Lecture 13. Persistence b/subtitles/en/Lecture 13. Persistence new file mode 100644 index 0000000..bc66226 --- /dev/null +++ b/subtitles/en/Lecture 13. Persistence @@ -0,0 +1,6501 @@ +1 +00:00:00,425 --> 00:00:03,508 +(enlightening music) + +2 +00:00:04,920 --> 00:00:06,620 +- [Announcer] Stanford University. + +3 +00:00:09,470 --> 00:00:12,360 +- [Lecturer] All righty then, Lecture 13 + +4 +00:00:12,360 --> 00:00:17,050 +of Stanford CS193p Spring of 2020. + +5 +00:00:17,050 --> 00:00:20,150 +Today, our topic is persistence. + +6 +00:00:20,150 --> 00:00:23,900 +That is to say, storing stuff that lives + +7 +00:00:23,900 --> 00:00:27,430 +between launches of your application. + +8 +00:00:27,430 --> 00:00:28,960 +Now, we've actually seen quite + +9 +00:00:28,960 --> 00:00:31,100 +a bit of this stuff already. + +10 +00:00:31,100 --> 00:00:34,490 +And we're gonna go into some more detail + +11 +00:00:34,490 --> 00:00:37,890 +on the last two down there, +CloudKit and file system + +12 +00:00:37,890 --> 00:00:39,460 +but let's do a quick review + +13 +00:00:39,460 --> 00:00:41,100 +of what we've learned about persistence. + +14 +00:00:41,100 --> 00:00:42,870 +We know about UserDefaults. + +15 +00:00:42,870 --> 00:00:46,390 +It's simple, quite limited, +only lets you store + +16 +00:00:46,390 --> 00:00:47,960 +these property lists. + +17 +00:00:47,960 --> 00:00:50,820 +It's small, it only stores +a little bit of data. + +18 +00:00:50,820 --> 00:00:55,420 +It's also pre-Swift, just +kind of a clunky API. + +19 +00:00:55,420 --> 00:00:56,940 +But it's really good for demos, + +20 +00:00:56,940 --> 00:00:59,973 +and that's why we've used +it so much this quarter. + +21 +00:01:00,908 --> 00:01:04,600 +And we learned about Codable +and JSON earlier as well. + +22 +00:01:04,600 --> 00:01:07,490 +Great way to take a custom struct + +23 +00:01:07,490 --> 00:01:09,390 +that we've designed and turn it + +24 +00:01:09,390 --> 00:01:12,210 +into nice interoperable format, + +25 +00:01:12,210 --> 00:01:14,640 +either that we would +send over the internet, + +26 +00:01:14,640 --> 00:01:18,260 +or maybe that we would store on disk. + +27 +00:01:18,260 --> 00:01:20,082 +Now, for those of you who looked into + +28 +00:01:20,082 --> 00:01:22,460 +the Enroute code that I wrote + +29 +00:01:22,460 --> 00:01:24,970 +that got the data from FlightAware + +30 +00:01:24,970 --> 00:01:27,160 +would see that that data from FlightAware + +31 +00:01:27,160 --> 00:01:30,370 +comes as JSON, and I just use Codable + +32 +00:01:30,370 --> 00:01:32,500 +to turn it into a local struct. + +33 +00:01:32,500 --> 00:01:34,830 +So that's another use of Codable + +34 +00:01:34,830 --> 00:01:39,463 +is receiving data from +people in JSON format. + +35 +00:01:40,720 --> 00:01:45,560 +This UIDocument is something +that is part of UIKit. + +36 +00:01:45,560 --> 00:01:48,490 +So we're not really gonna +talk about it in this class + +37 +00:01:48,490 --> 00:01:49,870 +since this is a SwiftUI class. + +38 +00:01:49,870 --> 00:01:53,343 +However, if you have an +application like EmojiArt + +39 +00:01:53,343 --> 00:01:55,900 +that really has what the user perceives + +40 +00:01:55,900 --> 00:01:58,790 +to be a document that they're creating, + +41 +00:01:58,790 --> 00:02:00,650 +you almost certainly would wanna use + +42 +00:02:00,650 --> 00:02:03,210 +this UIDocument infrastructure. + +43 +00:02:03,210 --> 00:02:04,600 +This is not gonna be something + +44 +00:02:04,600 --> 00:02:07,142 +that you're gonna do +for your final project. + +45 +00:02:07,142 --> 00:02:10,500 +It's not just that it's +a really advanced API, + +46 +00:02:10,500 --> 00:02:13,650 +as much as it requires UIkit integration, + +47 +00:02:13,650 --> 00:02:15,900 +and some concepts there that we just + +48 +00:02:15,900 --> 00:02:18,360 +don't have time to cover, bottom line, + +49 +00:02:18,360 --> 00:02:20,200 +but I'm mentioning it just so you know + +50 +00:02:20,200 --> 00:02:21,660 +it's out there because when you, + +51 +00:02:21,660 --> 00:02:22,760 +if you went out in the real world, + +52 +00:02:22,760 --> 00:02:25,130 +and you created some kind +of app that has a document, + +53 +00:02:25,130 --> 00:02:26,983 +you wanna know about UIDocuments. + +54 +00:02:28,600 --> 00:02:30,620 +And there's Core Data, of course, + +55 +00:02:30,620 --> 00:02:32,960 +powerful, object-oriented, + +56 +00:02:32,960 --> 00:02:35,840 +it's incredibly great SwiftUI integration + +57 +00:02:35,840 --> 00:02:38,650 +through that FetchedResults stuff. + +58 +00:02:38,650 --> 00:02:40,960 +And this is really the go-to place, + +59 +00:02:40,960 --> 00:02:44,144 +when we want to store data in an iOS app, + +60 +00:02:44,144 --> 00:02:45,635 +we're gonna Core Data. + +61 +00:02:45,635 --> 00:02:47,344 +For any significant amount of data, + +62 +00:02:47,344 --> 00:02:48,177 +we're gonna do this. + +63 +00:02:48,177 --> 00:02:49,835 +We're not gonna put it in UserDefaults + +64 +00:02:49,835 --> 00:02:51,286 +unless we're doing a demo. + +65 +00:02:51,286 --> 00:02:52,970 +We're gonna use Core +Data, and you saw why, + +66 +00:02:52,970 --> 00:02:56,673 +it's really very capable database system. + +67 +00:02:59,110 --> 00:03:03,580 +CloudKit is something I'm +gonna talk about today. + +68 +00:03:03,580 --> 00:03:08,330 +And it's a way to store data +in on the network in iCloud. + +69 +00:03:08,330 --> 00:03:11,730 +And you can see there's some +huge advantages of doing that. + +70 +00:03:11,730 --> 00:03:13,560 +When you put stuff out on the network, + +71 +00:03:13,560 --> 00:03:15,510 +it means that now, the +user's gonna see all + +72 +00:03:15,510 --> 00:03:17,890 +that data on all of their devices, + +73 +00:03:17,890 --> 00:03:19,680 +instead of just on the device they created + +74 +00:03:19,680 --> 00:03:24,150 +the EmojiArt thing or the +theme in their Memorize. + +75 +00:03:24,150 --> 00:03:27,040 +So it's really, really powerful thing + +76 +00:03:27,040 --> 00:03:29,980 +to be able to do, store +things on the network. + +77 +00:03:29,980 --> 00:03:33,030 +CloudKit has some nice features + +78 +00:03:33,030 --> 00:03:35,810 +that are similar to what you already know, + +79 +00:03:35,810 --> 00:03:38,460 +for example, it has its +own little UserDefaults + +80 +00:03:38,460 --> 00:03:42,360 +like thing, where you +can store key-value pairs + +81 +00:03:42,360 --> 00:03:46,310 +on the network that are shared +on all devices for that user. + +82 +00:03:46,310 --> 00:03:48,980 +And it also can play really +nicely with Core Data. + +83 +00:03:48,980 --> 00:03:52,190 +I know if you remember when +we did the new project, + +84 +00:03:52,190 --> 00:03:54,630 +and we clicked the Use +Core Data button there, + +85 +00:03:54,630 --> 00:03:57,983 +there was another one that +said, "Oh and Use CloudKit too." + +86 +00:03:57,983 --> 00:04:00,540 +And now, we'll make it so +that your Core Data databases + +87 +00:04:00,540 --> 00:04:02,720 +get replicated using CloudKit + +88 +00:04:02,720 --> 00:04:05,170 +on all of the user's devices. + +89 +00:04:05,170 --> 00:04:07,220 +So anything they put in Core +Data, they see everywhere. + +90 +00:04:07,220 --> 00:04:10,363 +That's a powerful combo right there. + +91 +00:04:11,706 --> 00:04:13,210 +And CloudKit also has mechanism + +92 +00:04:13,210 --> 00:04:15,860 +for storing documents out there. + +93 +00:04:15,860 --> 00:04:19,340 +So there's some integration +with UIDocument and all that, + +94 +00:04:19,340 --> 00:04:22,170 +to make a document store, +so CloudKit's really, + +95 +00:04:22,170 --> 00:04:25,080 +iCloud in general, +really awesome mechanism + +96 +00:04:25,080 --> 00:04:27,050 +for saving things on the network + +97 +00:04:27,050 --> 00:04:29,783 +so the user can see them +on all of their devices. + +98 +00:04:30,640 --> 00:04:32,120 +Now, we're gonna go over the basics + +99 +00:04:32,120 --> 00:04:33,660 +of CloudKit today via slide. + +100 +00:04:33,660 --> 00:04:36,180 +I just wanna give you a +feel for what it's like. + +101 +00:04:36,180 --> 00:04:38,440 +This is an API you might wanna try + +102 +00:04:38,440 --> 00:04:39,980 +and use for your final project. + +103 +00:04:39,980 --> 00:04:40,940 +It's a little ambitious, + +104 +00:04:40,940 --> 00:04:44,320 +and I'm gonna show you +ways you can cut corners + +105 +00:04:44,320 --> 00:04:46,340 +just a little bit for your final project + +106 +00:04:46,340 --> 00:04:48,380 +as soon as you introduce yourself to this. + +107 +00:04:48,380 --> 00:04:51,003 +This is an introductory course after all. + +108 +00:04:51,850 --> 00:04:53,347 +But I think some of you might find, + +109 +00:04:53,347 --> 00:04:56,647 +"Wow, I really need a way to store stuff + +110 +00:04:56,647 --> 00:04:59,360 +"that would work on all +the user's devices." + +111 +00:04:59,360 --> 00:05:01,430 +And so, CloudKit might be a nice + +112 +00:05:01,430 --> 00:05:03,693 +your-choice API from the rubric. + +113 +00:05:05,220 --> 00:05:06,560 +Then, the next stuff to talk about + +114 +00:05:06,560 --> 00:05:09,780 +after CloudKit is the file system + +115 +00:05:09,780 --> 00:05:11,590 +essentially accessing +anything in the file system, + +116 +00:05:11,590 --> 00:05:14,150 +which we do via URL and Data, + +117 +00:05:14,150 --> 00:05:15,950 +which you already know +about those structs, + +118 +00:05:15,950 --> 00:05:19,030 +and also a new struct called FileManager. + +119 +00:05:19,030 --> 00:05:20,420 +I'll talk about how these things work, + +120 +00:05:20,420 --> 00:05:23,070 +and then, I'm actually +gonna demo on this one, + +121 +00:05:23,070 --> 00:05:24,970 +where we're gonna make +our EmojiArtDocuments + +122 +00:05:24,970 --> 00:05:26,853 +be stored in the file system. + +123 +00:05:28,780 --> 00:05:30,160 +So CloudKit, what is it? + +124 +00:05:30,160 --> 00:05:32,630 +It's a database in the cloud. + +125 +00:05:32,630 --> 00:05:35,570 +Now, it's a simple to use database, + +126 +00:05:35,570 --> 00:05:37,580 +has basic database operation, + +127 +00:05:37,580 --> 00:05:39,920 +not as fully featured as Core Data. + +128 +00:05:39,920 --> 00:05:43,510 +This is not Core Data over +the network, all right. + +129 +00:05:43,510 --> 00:05:44,570 +Now, one of the most important things + +130 +00:05:44,570 --> 00:05:46,870 +to understand about +doing CloudKit database + +131 +00:05:46,870 --> 00:05:49,130 +is that it's asynchronous. + +132 +00:05:49,130 --> 00:05:52,550 +All of the important calls that do things + +133 +00:05:52,550 --> 00:05:54,650 +in CloudKit are asynchronous. + +134 +00:05:54,650 --> 00:05:56,210 +You provide them a closure, + +135 +00:05:56,210 --> 00:05:58,360 +it goes off and does it +on a background thread, + +136 +00:05:58,360 --> 00:06:00,570 +and when it's done, it +calls your closure back, + +137 +00:06:00,570 --> 00:06:02,450 +and said here's what happened. + +138 +00:06:02,450 --> 00:06:04,990 +That kind of programming, +asynchronous programming, + +139 +00:06:04,990 --> 00:06:06,090 +takes some getting used to. + +140 +00:06:06,090 --> 00:06:08,487 +You already saw it a little +bit so far in this course. + +141 +00:06:08,487 --> 00:06:11,300 +But CloudKit is intensively asynchronous. + +142 +00:06:11,300 --> 00:06:13,070 +By its very nature, it's going out + +143 +00:06:13,070 --> 00:06:14,450 +over the network, which the network + +144 +00:06:14,450 --> 00:06:17,203 +might be unavailable or it +might be slow, or whatever. + +145 +00:06:18,380 --> 00:06:21,830 +Demoing this is, because of that, + +146 +00:06:21,830 --> 00:06:23,510 +can be quite a big demo, + +147 +00:06:23,510 --> 00:06:25,820 +even bigger than Core Data demo. + +148 +00:06:25,820 --> 00:06:27,820 +So I'm not gonna do a demo this quarter. + +149 +00:06:27,820 --> 00:06:31,260 +If you want to go back +to spring of 2015-16, + +150 +00:06:31,260 --> 00:06:33,520 +this course was on iTunesU. + +151 +00:06:33,520 --> 00:06:35,470 +You can, I think it's +still there on iTunesU, + +152 +00:06:35,470 --> 00:06:38,950 +you can go watch it, and +see the CloudKit demo + +153 +00:06:38,950 --> 00:06:40,880 +that we did and most of +that is still applicable. + +154 +00:06:40,880 --> 00:06:45,070 +This, all this cloud stuff is +pre-SwiftUI, pre-Swift even. + +155 +00:06:45,070 --> 00:06:49,180 +And so, the stuff hasn't +changed that much since then, + +156 +00:06:49,180 --> 00:06:50,370 +you'll get the basic idea + +157 +00:06:50,370 --> 00:06:52,170 +if you wanna go back and watch that. + +158 +00:06:53,570 --> 00:06:56,210 +All right, so let's do +an overview of CloudKit. + +159 +00:06:56,210 --> 00:06:58,680 +I just wanna define some terms + +160 +00:06:58,680 --> 00:07:00,050 +that we use in CloudKit a lot, + +161 +00:07:00,050 --> 00:07:02,060 +so we understand what we're talking about. + +162 +00:07:02,060 --> 00:07:05,100 +The first term is Record Type. + +163 +00:07:05,100 --> 00:07:08,110 +So a Record Type is like +a class or a struct. + +164 +00:07:08,110 --> 00:07:11,500 +There's really no classes +or structs per se, + +165 +00:07:11,500 --> 00:07:12,900 +stored in CloudKit. + +166 +00:07:12,900 --> 00:07:14,180 +It's not like Core Data, + +167 +00:07:14,180 --> 00:07:17,180 +where we essentially +looks like objects to us, + +168 +00:07:17,180 --> 00:07:19,150 +but we do have these +things called Record Types, + +169 +00:07:19,150 --> 00:07:23,030 +and that's a kind of thing +that's in the database. + +170 +00:07:23,030 --> 00:07:26,750 +Then, the word "Fields" +is what we use for vars. + +171 +00:07:26,750 --> 00:07:29,500 +In Core Data, we call these attributes. + +172 +00:07:29,500 --> 00:07:31,170 +In CloudKit, we call them Fields. + +173 +00:07:31,170 --> 00:07:33,630 +This is the vars, the things that exist + +174 +00:07:33,630 --> 00:07:37,030 +in our Record Types that we store. + +175 +00:07:37,030 --> 00:07:38,610 +Then, there's the word Record. + +176 +00:07:38,610 --> 00:07:41,070 +Record means an instance of a Record Type, + +177 +00:07:41,070 --> 00:07:44,160 +so it's an actual one of +those things in the database, + +178 +00:07:44,160 --> 00:07:45,270 +so of course, you're +gonna be storing many, + +179 +00:07:45,270 --> 00:07:48,791 +many Records in your CloudKit database. + +180 +00:07:48,791 --> 00:07:50,037 +And that's where all your data is, + +181 +00:07:50,037 --> 00:07:53,243 +and the Records contain +values for all the Fields. + +182 +00:07:54,740 --> 00:07:56,560 +There's something called a Reference, + +183 +00:07:56,560 --> 00:07:59,139 +capital R, Reference, a CKReference. + +184 +00:07:59,139 --> 00:08:01,040 +You're gonna see CK in +front of all the things + +185 +00:08:01,040 --> 00:08:02,393 +that we do in CloudKit. + +186 +00:08:03,380 --> 00:08:06,010 +And that is a pointer to another Record, + +187 +00:08:06,010 --> 00:08:10,490 +doing relationships between Records, + +188 +00:08:10,490 --> 00:08:12,880 +Record Types, is not quite the same, + +189 +00:08:12,880 --> 00:08:14,900 +or as powerful if you're having Core Data, + +190 +00:08:14,900 --> 00:08:17,660 +where it's automatically +keeping a set of the objects + +191 +00:08:17,660 --> 00:08:19,560 +on the other side, and +it keeps it up to date, + +192 +00:08:19,560 --> 00:08:21,280 +and all that business. + +193 +00:08:21,280 --> 00:08:24,330 +This is not a full relational +database by any means here. + +194 +00:08:24,330 --> 00:08:26,850 +So references between +objects still make sense + +195 +00:08:26,850 --> 00:08:29,870 +but you have to do them +with this CKReference, + +196 +00:08:29,870 --> 00:08:31,540 +this Reference to the other object, + +197 +00:08:31,540 --> 00:08:34,300 +and I'll show you that, what +that looks like in code. + +198 +00:08:34,300 --> 00:08:37,720 +Then, there are terms like +Database, Zone and Container. + +199 +00:08:37,720 --> 00:08:39,530 +A Container is a collection of Databases. + +200 +00:08:39,530 --> 00:08:41,800 +A Database can have Zones inside of it. + +201 +00:08:41,800 --> 00:08:44,380 +This is just how we partition up the space + +202 +00:08:44,380 --> 00:08:47,797 +out in iCloud that we +want to store our data in, + +203 +00:08:47,797 --> 00:08:50,560 +and I'm gonna talk a little +bit briefly about this. + +204 +00:08:50,560 --> 00:08:53,550 +I'll talk mostly about +the top level databases + +205 +00:08:53,550 --> 00:08:55,090 +that we use, where you're gonna use one + +206 +00:08:55,090 --> 00:08:57,140 +of three databases, and you can see that. + +207 +00:08:58,430 --> 00:09:00,070 +Then, there's something called a Query. + +208 +00:09:00,070 --> 00:09:02,210 +A Query is a Database search. + +209 +00:09:02,210 --> 00:09:03,450 +This is where we're gonna +go out in the Database, + +210 +00:09:03,450 --> 00:09:05,170 +and try and find some Records, + +211 +00:09:05,170 --> 00:09:07,560 +some instances of some Record Types + +212 +00:09:07,560 --> 00:09:09,340 +that match some criteria. + +213 +00:09:09,340 --> 00:09:10,273 +And that's gonna look very familiar to you + +214 +00:09:10,273 --> 00:09:11,840 +when we get to that. + +215 +00:09:11,840 --> 00:09:14,120 +And finally, there is a Subscription. + +216 +00:09:14,120 --> 00:09:15,757 +So this is like a standing Query, + +217 +00:09:15,757 --> 00:09:17,830 +and we talked about standing queries + +218 +00:09:17,830 --> 00:09:21,812 +in Core Data, where we have +the SwiftUI FetchRequests + +219 +00:09:21,812 --> 00:09:23,000 +that return the these FetchedResults, + +220 +00:09:23,000 --> 00:09:24,240 +and that was a standing query, + +221 +00:09:24,240 --> 00:09:26,110 +it was always updating them. + +222 +00:09:26,110 --> 00:09:28,130 +Well, here's a standing query too + +223 +00:09:28,130 --> 00:09:30,090 +but it's a lot more complicated + +224 +00:09:30,090 --> 00:09:32,390 +to have a standing query on the network, + +225 +00:09:32,390 --> 00:09:34,440 +because you're talking about finding out + +226 +00:09:34,440 --> 00:09:36,660 +when something changes in iCloud, + +227 +00:09:36,660 --> 00:09:38,950 +and then, notifying your app, whoa, + +228 +00:09:38,950 --> 00:09:42,560 +this Query that you set +up to be always querying, + +229 +00:09:42,560 --> 00:09:44,210 +it changed but it changed on the network, + +230 +00:09:44,210 --> 00:09:46,790 +and you get notified, and the +way your app gets notified + +231 +00:09:46,790 --> 00:09:49,160 +is via something called +a push notification. + +232 +00:09:49,160 --> 00:09:51,870 +These are the little things +that come down to your phone + +233 +00:09:51,870 --> 00:09:53,740 +and tell you certain things have happened. + +234 +00:09:53,740 --> 00:09:56,300 +A lot of apps have these +push notifications. + +235 +00:09:56,300 --> 00:09:57,750 +And that's how this works. + +236 +00:09:57,750 --> 00:09:59,760 +Now, that's way beyond +the scope of this class + +237 +00:09:59,760 --> 00:10:01,560 +to talk about how push notifications work, + +238 +00:10:01,560 --> 00:10:03,540 +and how you would react to them. + +239 +00:10:03,540 --> 00:10:05,070 +This is not something I would expect you + +240 +00:10:05,070 --> 00:10:06,630 +to do on your final project is to have + +241 +00:10:06,630 --> 00:10:08,810 +a Subscription, a standing Query, + +242 +00:10:08,810 --> 00:10:11,710 +and handle the push notifications. + +243 +00:10:11,710 --> 00:10:13,310 +You have three weeks to do your project. + +244 +00:10:13,310 --> 00:10:14,740 +I don't want you spending +a whole week on it, + +245 +00:10:14,740 --> 00:10:16,500 +trying to do that so I would, + +246 +00:10:16,500 --> 00:10:18,340 +if you're gonna do CloudKit +for your final project, + +247 +00:10:18,340 --> 00:10:21,113 +I would not tackle Subscriptions. + +248 +00:10:22,020 --> 00:10:24,170 +One thing about using CloudKit + +249 +00:10:24,170 --> 00:10:26,220 +is it requires a little bit of enabling. + +250 +00:10:26,220 --> 00:10:28,810 +You're used to just, I don't +know, import Core Data, + +251 +00:10:28,810 --> 00:10:30,110 +and I can start using Core Data, + +252 +00:10:30,110 --> 00:10:31,530 +and that's true for Core Data, + +253 +00:10:31,530 --> 00:10:34,290 +but for CloudKit, you +actually need to turn it on. + +254 +00:10:34,290 --> 00:10:37,310 +And if you go to the Capabilities tab + +255 +00:10:37,310 --> 00:10:38,960 +in your Project Settings, you're gonna see + +256 +00:10:38,960 --> 00:10:41,610 +there's a bunch of +capabilities like Apple Pay, + +257 +00:10:41,610 --> 00:10:44,380 +and Game Center, and things like that, + +258 +00:10:44,380 --> 00:10:45,550 +that you have to turn on, + +259 +00:10:45,550 --> 00:10:47,640 +and that's because these things + +260 +00:10:47,640 --> 00:10:50,280 +are accessing servers +out there in the world, + +261 +00:10:50,280 --> 00:10:53,340 +so they need a little +bit of an authorization + +262 +00:10:53,340 --> 00:10:56,480 +and enablement, entitlements +we call these things + +263 +00:10:56,480 --> 00:10:58,770 +to make your app be able to do these. + +264 +00:10:58,770 --> 00:10:59,870 +But it's quite easy to do. + +265 +00:10:59,870 --> 00:11:02,410 +You just go in here to +this Capabilities tab, + +266 +00:11:02,410 --> 00:11:04,930 +and we see iCloud, it says +"OFF" when you get in there. + +267 +00:11:04,930 --> 00:11:06,970 +Just click it to "ON", and you're gonna + +268 +00:11:06,970 --> 00:11:08,610 +get some more UI here, + +269 +00:11:08,610 --> 00:11:10,300 +and you can see there's three different + +270 +00:11:10,300 --> 00:11:12,160 +services in CloudKit. + +271 +00:11:12,160 --> 00:11:14,160 +The first one there, key-value storage, + +272 +00:11:14,160 --> 00:11:16,040 +that's the UserDefaults like thing + +273 +00:11:16,040 --> 00:11:17,080 +I was telling you about, + +274 +00:11:17,080 --> 00:11:18,750 +and then, iCloud Documents right there. + +275 +00:11:18,750 --> 00:11:20,953 +That's for storing your +documents in iCloud. + +276 +00:11:20,953 --> 00:11:22,240 +I was telling you about that. + +277 +00:11:22,240 --> 00:11:24,400 +And what we're gonna +talk about is CloudKit, + +278 +00:11:24,400 --> 00:11:26,380 +which is this database, right, + +279 +00:11:26,380 --> 00:11:29,090 +the Database, the Records, +and Fields, and all that. + +280 +00:11:29,090 --> 00:11:30,440 +So you're gonna turn that on, + +281 +00:11:30,440 --> 00:11:33,630 +and then, you're gonna go down +to this button right below, + +282 +00:11:33,630 --> 00:11:36,960 +very important button, CloudKit Dashboard, + +283 +00:11:36,960 --> 00:11:38,680 +this CloudKit Dashboard is gonna let you + +284 +00:11:38,680 --> 00:11:41,500 +manage all your activity in CloudKit, + +285 +00:11:41,500 --> 00:11:43,500 +all your Record Types, all your Records, + +286 +00:11:43,500 --> 00:11:45,610 +see all your data queries, + +287 +00:11:45,610 --> 00:11:49,510 +everything is going to +be managed through this. + +288 +00:11:49,510 --> 00:11:50,780 +Let's click on this button, + +289 +00:11:50,780 --> 00:11:52,860 +or simulate clicking on this button, + +290 +00:11:52,860 --> 00:11:54,650 +and see what we get. + +291 +00:11:54,650 --> 00:11:55,980 +This is what you get, + +292 +00:11:55,980 --> 00:11:59,130 +you go to a certain +website on the internet, + +293 +00:11:59,130 --> 00:12:01,270 +and it probably doesn't look exactly + +294 +00:12:01,270 --> 00:12:04,740 +like this anymore, this like, +it says created May 15, 2016, + +295 +00:12:04,740 --> 00:12:07,450 +so this is kinda old, +but it's still same idea + +296 +00:12:07,450 --> 00:12:09,380 +what's going on up there, + +297 +00:12:09,380 --> 00:12:12,750 +which is that you are +looking at all the Records + +298 +00:12:12,750 --> 00:12:14,380 +and Record Types that you have, + +299 +00:12:14,380 --> 00:12:15,795 +and you're even marking them. + +300 +00:12:15,795 --> 00:12:16,628 +You see on the right there + +301 +00:12:16,628 --> 00:12:18,690 +which is Query, Search, +Sort, Query, Search. + +302 +00:12:18,690 --> 00:12:20,210 +You're marking which things + +303 +00:12:20,210 --> 00:12:21,840 +you wanna be able to query, + +304 +00:12:21,840 --> 00:12:25,470 +and which things you wanna be +able to sort on, et cetera. + +305 +00:12:25,470 --> 00:12:27,620 +You can add Record Types, and Fields, + +306 +00:12:27,620 --> 00:12:28,760 +and all that stuff here, + +307 +00:12:28,760 --> 00:12:30,580 +although you usually don't do that + +308 +00:12:30,580 --> 00:12:33,010 +because something very +interesting about CloudKit + +309 +00:12:33,010 --> 00:12:36,300 +when it comes to adding +Record Types and Fields, + +310 +00:12:36,300 --> 00:12:39,370 +which is that it has +dynamic schema creation. + +311 +00:12:39,370 --> 00:12:41,450 +So you kind of look at that dashboard, + +312 +00:12:41,450 --> 00:12:43,507 +and you think, "Oh, +that's kinda like the map + +313 +00:12:43,507 --> 00:12:46,680 +"we had with Core Data," and it kinda is. + +314 +00:12:46,680 --> 00:12:48,520 +It serves a lot of the same function. + +315 +00:12:48,520 --> 00:12:51,110 +However, in Core Data, +you have to do the map. + +316 +00:12:51,110 --> 00:12:53,740 +The map is how your app knows + +317 +00:12:53,740 --> 00:12:56,350 +what classes and vars to create for you, + +318 +00:12:56,350 --> 00:12:59,960 +so you can access the +data, where in CloudKit, + +319 +00:12:59,960 --> 00:13:01,260 +you don't have to do the map. + +320 +00:13:01,260 --> 00:13:03,230 +It can build the map on the fly. + +321 +00:13:03,230 --> 00:13:06,260 +If you create a Record +Type with a certain name, + +322 +00:13:06,260 --> 00:13:09,240 +it just creates that very +first time you ever do it, + +323 +00:13:09,240 --> 00:13:10,190 +boom, it creates it. + +324 +00:13:10,190 --> 00:13:13,180 +Now, it only does this dynamic creation + +325 +00:13:13,180 --> 00:13:15,190 +of the Record Types, +and Fields, and stuff, + +326 +00:13:15,190 --> 00:13:16,770 +while you're in development, + +327 +00:13:16,770 --> 00:13:18,700 +and eventually, when your app ships, + +328 +00:13:18,700 --> 00:13:19,950 +when you go to App Store, + +329 +00:13:21,330 --> 00:13:22,870 +the iTunes Connect, where you set up + +330 +00:13:22,870 --> 00:13:25,010 +to have your app be on the App Store, + +331 +00:13:25,010 --> 00:13:25,917 +you're gonna click a button says, + +332 +00:13:25,917 --> 00:13:27,367 +"Okay, I'm switching over to production + +333 +00:13:27,367 --> 00:13:29,380 +"mode on my CloudKit," and then, + +334 +00:13:29,380 --> 00:13:31,690 +it's not gonna let you do +this dynamic schema creation, + +335 +00:13:31,690 --> 00:13:32,600 +of course, right. + +336 +00:13:32,600 --> 00:13:35,390 +You do the dynamic schema creation + +337 +00:13:35,390 --> 00:13:37,530 +while you're in development +once you get that + +338 +00:13:37,530 --> 00:13:40,330 +to the Record Types, and +Fields, and stuff you want, + +339 +00:13:40,330 --> 00:13:43,040 +then, you go live. + +340 +00:13:43,040 --> 00:13:45,720 +Let's take a look briefly +at what the code looks + +341 +00:13:45,720 --> 00:13:48,530 +like when you're writing a CloudKit app. + +342 +00:13:48,530 --> 00:13:51,763 +The first thing you need is +a Database to put things in. + +343 +00:13:51,763 --> 00:13:53,730 +It's kind of like a ManagedObjectContext + +344 +00:13:53,730 --> 00:13:55,380 +but not really 'cause it's much, + +345 +00:13:55,380 --> 00:13:58,040 +much more lighter weight +concept, this Database. + +346 +00:13:58,040 --> 00:13:59,530 +But the most important thing + +347 +00:13:59,530 --> 00:14:01,360 +you're choosing between +is whether you want + +348 +00:14:01,360 --> 00:14:03,930 +a public Database, a shared Database, + +349 +00:14:03,930 --> 00:14:05,920 +or the private Database. + +350 +00:14:05,920 --> 00:14:09,100 +So the private Database is +the normal iCloud Database. + +351 +00:14:09,100 --> 00:14:11,610 +This is just the Database +where you put stuff + +352 +00:14:11,610 --> 00:14:14,900 +that is the user's, and the user sees it + +353 +00:14:14,900 --> 00:14:17,990 +on all their devices, +that's the normal Database. + +354 +00:14:17,990 --> 00:14:21,570 +The shared and public are +kind of interesting ones. + +355 +00:14:21,570 --> 00:14:24,600 +The public one, if you, +if a user puts stuff + +356 +00:14:24,600 --> 00:14:26,840 +in the public Database for themselves, + +357 +00:14:26,840 --> 00:14:30,760 +then, other users, if they +know that person's iCloud + +358 +00:14:31,950 --> 00:14:34,630 +email address or whatever, +they can actually look + +359 +00:14:34,630 --> 00:14:37,390 +their app, and go look, and see that data. + +360 +00:14:37,390 --> 00:14:40,000 +So it's really kind of +publicly posted data. + +361 +00:14:40,000 --> 00:14:43,090 +You can think of it as like your website, + +362 +00:14:43,090 --> 00:14:45,510 +making the stuff available to people, + +363 +00:14:45,510 --> 00:14:47,050 +and they can see it all they want. + +364 +00:14:47,050 --> 00:14:48,927 +Pretty rare to do this on iCloud, + +365 +00:14:48,927 --> 00:14:49,940 +but you could do it. + +366 +00:14:49,940 --> 00:14:51,340 +Essentially, a way to use iCloud + +367 +00:14:51,340 --> 00:14:53,800 +to publish information to the world. + +368 +00:14:53,800 --> 00:14:56,630 +And then, they're shared, +which is invitation- + +369 +00:14:56,630 --> 00:14:59,117 +only access to your private Database. + +370 +00:14:59,117 --> 00:15:01,410 +And the way this works is you end up + +371 +00:15:01,410 --> 00:15:04,110 +sending an email to people. + +372 +00:15:04,110 --> 00:15:05,600 +And in that email is a link, + +373 +00:15:05,600 --> 00:15:06,840 +and when they click on it, + +374 +00:15:06,840 --> 00:15:10,050 +their little iCloud shared Database + +375 +00:15:10,050 --> 00:15:14,110 +gets a view onto some +part of, not your entire, + +376 +00:15:14,110 --> 00:15:16,600 +private cloud Database of someone else. + +377 +00:15:16,600 --> 00:15:18,380 +So that way, the two +of you can share data, + +378 +00:15:18,380 --> 00:15:20,680 +and both sides can add objects, + +379 +00:15:20,680 --> 00:15:23,080 +or whatever depending on +the permissions granted. + +380 +00:15:23,080 --> 00:15:24,880 +Add objects and see each other's objects, + +381 +00:15:24,880 --> 00:15:26,580 +and again, it's only a little sub-part, + +382 +00:15:26,580 --> 00:15:29,920 +so a little sub-part of the Database, + +383 +00:15:29,920 --> 00:15:32,873 +but it's a kind of a +cool way to share things. + +384 +00:15:34,180 --> 00:15:35,420 +So once you have a Database, + +385 +00:15:35,420 --> 00:15:36,920 +then, you can start creating Records, + +386 +00:15:36,920 --> 00:15:38,440 +and here's how you do that. + +387 +00:15:38,440 --> 00:15:39,800 +To create a Record, you just say + +388 +00:15:39,800 --> 00:15:42,280 +CKRecord and the name of the Record, + +389 +00:15:42,280 --> 00:15:43,900 +and again you don't have to have gone + +390 +00:15:43,900 --> 00:15:45,070 +to the dashboards first. + +391 +00:15:45,070 --> 00:15:47,150 +You can just do this, and +if this is the first time + +392 +00:15:47,150 --> 00:15:50,120 +ever created a CKRecord "Tweet", + +393 +00:15:50,120 --> 00:15:53,070 +then now Tweets, or Record Type Tweet, + +394 +00:15:53,070 --> 00:15:55,840 +is just going to be created +in the Database for you. + +395 +00:15:55,840 --> 00:15:57,940 +And then, to set the values of Fields, + +396 +00:15:57,940 --> 00:16:00,370 +that kind of looks like +accessing a Dictionary, + +397 +00:16:00,370 --> 00:16:04,040 +you say tweet open square +bracket the name of the Field, + +398 +00:16:04,040 --> 00:16:06,230 +equals the value, and that is going + +399 +00:16:06,230 --> 00:16:10,700 +to again create that text +Field in the Tweet Record Type, + +400 +00:16:10,700 --> 00:16:12,000 +if that doesn't exist before, + +401 +00:16:12,000 --> 00:16:14,280 +and set its value to that. + +402 +00:16:14,280 --> 00:16:15,680 +And here, I'll create another one. + +403 +00:16:15,680 --> 00:16:17,930 +This is a CKRecord for a Twitter user. + +404 +00:16:17,930 --> 00:16:19,380 +So it's a different Record Type, + +405 +00:16:19,380 --> 00:16:20,750 +a different kind of thing. + +406 +00:16:20,750 --> 00:16:22,320 +I'm going back to my tweet + +407 +00:16:22,320 --> 00:16:25,260 +and setting its "tweeter" Field + +408 +00:16:25,260 --> 00:16:28,230 +to be a Reference to the tweeter. + +409 +00:16:28,230 --> 00:16:30,263 +So see here, I'm having to say CKReference + +410 +00:16:30,263 --> 00:16:33,563 +with the record of this +TwitterUser I created. + +411 +00:16:34,660 --> 00:16:36,100 +A little different again from Core Data. + +412 +00:16:36,100 --> 00:16:37,230 +You can't just set it directly, + +413 +00:16:37,230 --> 00:16:38,860 +you gotta do a CKReference thing, + +414 +00:16:38,860 --> 00:16:40,250 +and then, notice that action + +415 +00:16:40,250 --> 00:16:42,710 +that says things like basically + +416 +00:16:42,710 --> 00:16:44,890 +determines what happens +if the Tweet gets deleted. + +417 +00:16:44,890 --> 00:16:46,650 +Does the TwitterUser get deleted? + +418 +00:16:46,650 --> 00:16:49,263 +Things like that, those +kinda relationships. + +419 +00:16:50,180 --> 00:16:52,550 +So that's how we build +up our Record Types, + +420 +00:16:52,550 --> 00:16:54,980 +and our Records, and their Fields, + +421 +00:16:54,980 --> 00:16:57,630 +and the References to other objects. + +422 +00:16:57,630 --> 00:16:59,240 +And once we've kinda done that, + +423 +00:16:59,240 --> 00:17:00,710 +then, we wanna save it. + +424 +00:17:00,710 --> 00:17:02,810 +And this is where we're +gonna hit the network. + +425 +00:17:02,810 --> 00:17:05,390 +So this is an asynchronous function. + +426 +00:17:05,390 --> 00:17:07,580 +Just call save, we just +give it the Record, + +427 +00:17:07,580 --> 00:17:10,060 +the CKRecord you wanna save, + +428 +00:17:10,060 --> 00:17:14,830 +and it's going to go off on +the network in the background. + +429 +00:17:14,830 --> 00:17:16,880 +It might take a long time +if the network's down + +430 +00:17:16,880 --> 00:17:19,430 +or might fail if the +network's down eventually, + +431 +00:17:19,430 --> 00:17:21,160 +but if it can finally get through, + +432 +00:17:21,160 --> 00:17:22,840 +and write the information that you want, + +433 +00:17:22,840 --> 00:17:25,278 +this Tweet Record, then it's gonna call + +434 +00:17:25,278 --> 00:17:27,827 +this closure that you give it back. + +435 +00:17:27,827 --> 00:17:31,490 +And this closure that you +give it has two arguments. + +436 +00:17:31,490 --> 00:17:34,943 +One is the record that it +saved, if it was successful, + +437 +00:17:34,943 --> 00:17:38,060 +and the other one is the +error that was generated + +438 +00:17:38,060 --> 00:17:39,510 +if it was not. + +439 +00:17:39,510 --> 00:17:41,040 +So this is again pre-Swift, + +440 +00:17:41,040 --> 00:17:42,760 +in Swift, we'd probably +have an enum in here + +441 +00:17:42,760 --> 00:17:44,300 +with success and failure, + +442 +00:17:44,300 --> 00:17:47,430 +and associated value of +the Record for success, + +443 +00:17:47,430 --> 00:17:49,090 +and associated value of the error + +444 +00:17:49,090 --> 00:17:49,923 +but we don't have any of that, + +445 +00:17:49,923 --> 00:17:51,133 +it's all pre-Swift. + +446 +00:17:52,070 --> 00:17:54,013 +So one or the other of these two things, + +447 +00:17:54,013 --> 00:17:56,240 +the savedRecord or the +error, it can be nil. + +448 +00:17:56,240 --> 00:17:58,840 +The error is nil, then whoa, success, + +449 +00:17:58,840 --> 00:18:01,010 +you saved that thing and the savedRecord + +450 +00:18:01,010 --> 00:18:03,710 +will be the CKRecord you just saved. + +451 +00:18:03,710 --> 00:18:05,260 +But if the error is not nil, + +452 +00:18:05,260 --> 00:18:07,480 +then, you gotta start +looking at the error codes, + +453 +00:18:07,480 --> 00:18:09,100 +and figure out what went wrong. + +454 +00:18:09,100 --> 00:18:12,370 +And it's the network, so a +lot of things can go wrong. + +455 +00:18:12,370 --> 00:18:16,490 +There are 29 different, at +last count, CKErrorCodes. + +456 +00:18:16,490 --> 00:18:18,040 +Now, you don't have to +check every single one + +457 +00:18:18,040 --> 00:18:20,270 +'cause some of them can't +happen during a save, + +458 +00:18:20,270 --> 00:18:22,840 +some errors happen in other things. + +459 +00:18:22,840 --> 00:18:25,340 +But if you're really doing this for real + +460 +00:18:25,340 --> 00:18:27,160 +and shipping your app, you'd want to check + +461 +00:18:27,160 --> 00:18:29,960 +all the ones that could +reasonably happen here, + +462 +00:18:29,960 --> 00:18:31,780 +and decide what your app is gonna do + +463 +00:18:31,780 --> 00:18:35,400 +because you weren't able +to save this Record. + +464 +00:18:35,400 --> 00:18:38,490 +Here's a place again if you're +doing your final project. + +465 +00:18:38,490 --> 00:18:40,420 +I'm not gonna hold it against you + +466 +00:18:40,420 --> 00:18:42,510 +if you don't check all these error codes. + +467 +00:18:42,510 --> 00:18:44,960 +Maybe check error codes in one place + +468 +00:18:44,960 --> 00:18:46,840 +just to show me you understand, + +469 +00:18:46,840 --> 00:18:48,750 +that you gotta check error codes, + +470 +00:18:48,750 --> 00:18:50,700 +but otherwise, don't check them. + +471 +00:18:50,700 --> 00:18:52,490 +And then your app, your final project + +472 +00:18:52,490 --> 00:18:54,450 +basically would just fail miserably + +473 +00:18:54,450 --> 00:18:57,393 +in bad networking conditions, +that's okay, we can. + +474 +00:18:58,240 --> 00:18:59,730 +This intro class, you're just trying + +475 +00:18:59,730 --> 00:19:02,870 +to introduce yourself to +API, so like CloudKit. + +476 +00:19:02,870 --> 00:19:06,120 +You're not trying to be a master of it all + +477 +00:19:06,120 --> 00:19:07,580 +by the end of this quarter. + +478 +00:19:07,580 --> 00:19:10,000 +And that reduces the scope quite a bit + +479 +00:19:10,000 --> 00:19:10,833 +of doing CloudKit. + +480 +00:19:10,833 --> 00:19:12,720 +A lot of CloudKit is +handling these errors, + +481 +00:19:12,720 --> 00:19:14,610 +and the infrastructure for what you do + +482 +00:19:14,610 --> 00:19:17,380 +when you can't write things out to iCloud. + +483 +00:19:17,380 --> 00:19:19,830 +And so hopefully, reduces +the scope to something + +484 +00:19:19,830 --> 00:19:21,840 +where you could realistically do it + +485 +00:19:21,840 --> 00:19:23,933 +as a final project API. + +486 +00:19:25,600 --> 00:19:27,390 +Now, what about querying Records, + +487 +00:19:27,390 --> 00:19:28,850 +searching for Records? + +488 +00:19:28,850 --> 00:19:31,310 +And this oughta real look familiar to you. + +489 +00:19:31,310 --> 00:19:32,450 +Yes, it's NSPredicate, + +490 +00:19:32,450 --> 00:19:35,410 +the exact same NSPredicate from Core Data. + +491 +00:19:35,410 --> 00:19:36,920 +It has the same object now. + +492 +00:19:36,920 --> 00:19:40,240 +You can't have exactly +the same formats there, + +493 +00:19:40,240 --> 00:19:43,210 +because the CloudKit database is not quite + +494 +00:19:43,210 --> 00:19:45,320 +as powerful as Core Data. + +495 +00:19:45,320 --> 00:19:46,900 +So Core Data can do some things in there + +496 +00:19:46,900 --> 00:19:50,170 +that CloudKit can't but +basic stuff like equals, + +497 +00:19:50,170 --> 00:19:53,580 +and does this text contain +this search String, + +498 +00:19:53,580 --> 00:19:55,760 +for example, this is, let's say a Tweet + +499 +00:19:55,760 --> 00:19:57,860 +that we're searching on right here, + +500 +00:19:57,860 --> 00:20:00,780 +that is perfectly reasonable to do. + +501 +00:20:00,780 --> 00:20:02,360 +So you create the Predicate you want, + +502 +00:20:02,360 --> 00:20:04,500 +and then, you create +something called a CKQuery, + +503 +00:20:04,500 --> 00:20:05,920 +which just is the Record Type + +504 +00:20:05,920 --> 00:20:08,040 +that you're trying to find, + +505 +00:20:08,040 --> 00:20:10,050 +that you're searching for essentially, + +506 +00:20:10,050 --> 00:20:12,227 +and that Predicate. + +507 +00:20:12,227 --> 00:20:15,210 +So again, sounds similar to a FetchRequest + +508 +00:20:15,210 --> 00:20:19,420 +in Core Data, similar, +but not exactly the same, + +509 +00:20:19,420 --> 00:20:21,281 +but you get the idea. + +510 +00:20:21,281 --> 00:20:22,270 +And then, to execute the Query, + +511 +00:20:22,270 --> 00:20:24,550 +of course, you're gonna have +to go out onto the network, + +512 +00:20:24,550 --> 00:20:27,900 +so that's where this +function perform comes in. + +513 +00:20:27,900 --> 00:20:29,110 +You give it the query you want, + +514 +00:20:29,110 --> 00:20:30,740 +and then, you give it a closure, + +515 +00:20:30,740 --> 00:20:32,050 +and that closure will be called + +516 +00:20:32,050 --> 00:20:34,570 +when this thing either fails or succeeds. + +517 +00:20:34,570 --> 00:20:36,390 +And that closure has +two arguments as well. + +518 +00:20:36,390 --> 00:20:39,290 +One is an Optional Array of the Records + +519 +00:20:39,290 --> 00:20:42,070 +that it found by doing +that search for you, + +520 +00:20:42,070 --> 00:20:43,950 +or an Error. + +521 +00:20:43,950 --> 00:20:45,550 +And again, if it's an Error, + +522 +00:20:45,550 --> 00:20:46,520 +you have to deal with the fact + +523 +00:20:46,520 --> 00:20:48,750 +things that you were looking for + +524 +00:20:48,750 --> 00:20:51,493 +failed to even search for them. + +525 +00:20:52,621 --> 00:20:54,890 +And if it's not, then the +Records will not be nil, + +526 +00:20:54,890 --> 00:20:55,723 +it'll be an array of CKRecord, + +527 +00:20:55,723 --> 00:20:58,237 +and there you go, there's your CKRecords + +528 +00:20:58,237 --> 00:20:59,630 +that you're looking for. + +529 +00:20:59,630 --> 00:21:02,180 +So fairly straightforward to do searching + +530 +00:21:02,180 --> 00:21:04,100 +in CloudKit as well. + +531 +00:21:04,100 --> 00:21:05,960 +These standing Queries are just, + +532 +00:21:05,960 --> 00:21:07,580 +you take one of those CKQueries, + +533 +00:21:07,580 --> 00:21:09,547 +and you essentially +communicate it to the database, + +534 +00:21:09,547 --> 00:21:12,130 +and then, it's doing the +Query on the server side, + +535 +00:21:12,130 --> 00:21:14,450 +and then, whenever a +new thing gets created, + +536 +00:21:14,450 --> 00:21:17,380 +that changes the result of that Query, + +537 +00:21:17,380 --> 00:21:20,030 +it's sent to this push notification. + +538 +00:21:20,030 --> 00:21:21,810 +And if you do want to try and check out + +539 +00:21:21,810 --> 00:21:23,820 +how do I handle push notifications, + +540 +00:21:23,820 --> 00:21:28,340 +and what do I do, feel free +to try and jump on that. + +541 +00:21:28,340 --> 00:21:30,010 +Again, I think a little too much + +542 +00:21:30,010 --> 00:21:32,000 +for your final project here. + +543 +00:21:32,000 --> 00:21:34,350 +You can take a look at the +UserNotifications framework, + +544 +00:21:34,350 --> 00:21:36,000 +not just for push notifications, + +545 +00:21:36,000 --> 00:21:37,820 +but also for doing +local notifications too. + +546 +00:21:37,820 --> 00:21:39,290 +You might wanna check that out. + +547 +00:21:39,290 --> 00:21:41,010 +Those are kinda fun, that's just where + +548 +00:21:41,010 --> 00:21:43,050 +you kinda can set little calendar events + +549 +00:21:43,050 --> 00:21:46,530 +almost, things to go +off at a certain time, + +550 +00:21:46,530 --> 00:21:49,390 +when your app wants to +remind the user of something, + +551 +00:21:49,390 --> 00:21:51,840 +or do something in a timely +manner, or something. + +552 +00:21:53,720 --> 00:21:55,020 +All right, that's it for CloudKit. + +553 +00:21:55,020 --> 00:21:56,810 +That's the intro to CloudKit. + +554 +00:21:56,810 --> 00:21:59,350 +Let's talk a little bit +about the file system, + +555 +00:21:59,350 --> 00:22:01,980 +iOS devices, I don't +know if y'all are aware + +556 +00:22:01,980 --> 00:22:05,090 +but they are essentially Unix OSes + +557 +00:22:05,090 --> 00:22:06,190 +at the heart of them, + +558 +00:22:06,190 --> 00:22:08,580 +and they have a Unix file system there, + +559 +00:22:08,580 --> 00:22:10,360 +Unix-like file system. + +560 +00:22:10,360 --> 00:22:11,660 +And it starts at slash, + +561 +00:22:11,660 --> 00:22:13,740 +just like all your Unix file systems, + +562 +00:22:13,740 --> 00:22:15,510 +but of course, it has protections, + +563 +00:22:15,510 --> 00:22:18,800 +and you cannot see or write into most + +564 +00:22:18,800 --> 00:22:20,570 +of the Unix file system there. + +565 +00:22:20,570 --> 00:22:22,910 +And there, you can see +and write into though + +566 +00:22:22,910 --> 00:22:25,180 +is called your sandbox. + +567 +00:22:25,180 --> 00:22:27,870 +And your sandbox completely isolates you + +568 +00:22:27,870 --> 00:22:28,950 +from the rest of the world. + +569 +00:22:28,950 --> 00:22:31,440 +Your app can't see into +other app sandboxes, + +570 +00:22:31,440 --> 00:22:33,160 +you can't see outside your sandbox + +571 +00:22:33,160 --> 00:22:34,730 +to modify the system, of course, + +572 +00:22:34,730 --> 00:22:36,117 +and damage it in any way, + +573 +00:22:36,117 --> 00:22:39,330 +and this is really a +great idea, sandboxes. + +574 +00:22:39,330 --> 00:22:42,180 +I wish we had this on Windows, and Mac, + +575 +00:22:42,180 --> 00:22:44,103 +and normal operating systems. + +576 +00:22:45,330 --> 00:22:47,440 +Obviously, it makes a ton +of sense on the devices, + +577 +00:22:47,440 --> 00:22:49,610 +where you're installing +and uninstalling these apps + +578 +00:22:49,610 --> 00:22:51,850 +for each of them to +have their own sandbox. + +579 +00:22:51,850 --> 00:22:53,920 +Now, why do we do this sandbox? + +580 +00:22:53,920 --> 00:22:55,170 +Three main reasons here. + +581 +00:22:55,170 --> 00:22:57,730 +One is security, you don't want anyone + +582 +00:22:57,730 --> 00:23:00,380 +to reach into your sandbox +and damage your app + +583 +00:23:00,380 --> 00:23:02,300 +in some way by affecting its data + +584 +00:23:02,300 --> 00:23:03,900 +or doing something bad. + +585 +00:23:03,900 --> 00:23:06,250 +Also privacy, your app, obviously, + +586 +00:23:06,250 --> 00:23:07,890 +is collecting data from the user, + +587 +00:23:07,890 --> 00:23:09,420 +and you don't want other apps + +588 +00:23:09,420 --> 00:23:11,657 +to be able to see what that data is. + +589 +00:23:11,657 --> 00:23:15,530 +And really underrated but +powerful part of it is cleanup. + +590 +00:23:15,530 --> 00:23:18,330 +If someone deletes your +app from your device, + +591 +00:23:18,330 --> 00:23:20,570 +you want everything that +app has ever created + +592 +00:23:20,570 --> 00:23:23,230 +or touched to disappear. + +593 +00:23:23,230 --> 00:23:25,760 +And that's what happens +when you delete your app. + +594 +00:23:25,760 --> 00:23:28,140 +The sandbox is completely removed, + +595 +00:23:28,140 --> 00:23:29,960 +and so everything the +person's ever created. + +596 +00:23:29,960 --> 00:23:33,030 +Now, the sandbox has directories in it, + +597 +00:23:33,030 --> 00:23:34,590 +which are backed up to iCloud, + +598 +00:23:34,590 --> 00:23:36,520 +when the user has iCloud Backups on. + +599 +00:23:36,520 --> 00:23:38,057 +So if someone deleted +an app and they said, + +600 +00:23:38,057 --> 00:23:40,910 +"Oh no, my documents were in there," + +601 +00:23:40,910 --> 00:23:43,620 +they can go back and get them. + +602 +00:23:43,620 --> 00:23:45,710 +By the way, when it comes +to storing documents, + +603 +00:23:45,710 --> 00:23:47,990 +a lot of times, we'd want to +store documents in iCloud. + +604 +00:23:47,990 --> 00:23:51,080 +That way if we deleted +an app off of my device, + +605 +00:23:51,080 --> 00:23:53,270 +it will still be on my other devices. + +606 +00:23:53,270 --> 00:23:54,630 +And if I reinstalled the app, + +607 +00:23:54,630 --> 00:23:56,655 +I would see them from iCloud. + +608 +00:23:56,655 --> 00:23:57,580 +That's why it's a really good idea + +609 +00:23:57,580 --> 00:23:59,667 +to store our documents in iCloud. + +610 +00:24:01,297 --> 00:24:03,730 +All right so what's in this sandbox? + +611 +00:24:03,730 --> 00:24:05,380 +Well, it's a bunch of directories, + +612 +00:24:05,380 --> 00:24:08,960 +special directories, kind of +specially named directories. + +613 +00:24:08,960 --> 00:24:11,560 +One of them is the Application directory. + +614 +00:24:11,560 --> 00:24:12,740 +This is where your executable is, + +615 +00:24:12,740 --> 00:24:15,320 +and your JPEGs, or +images, or anything else + +616 +00:24:15,320 --> 00:24:18,750 +that you drag into Xcode +to make your app work, + +617 +00:24:18,750 --> 00:24:20,990 +those live in there, and +they're read only there. + +618 +00:24:20,990 --> 00:24:23,800 +No, you're not allowed to +change your application, + +619 +00:24:23,800 --> 00:24:25,110 +add images to it or whatever, + +620 +00:24:25,110 --> 00:24:27,713 +you'd have to do that in other places. + +621 +00:24:28,840 --> 00:24:30,040 +Another really important directory + +622 +00:24:30,040 --> 00:24:32,140 +is the Documents directory. + +623 +00:24:32,140 --> 00:24:33,520 +This is where you store what + +624 +00:24:33,520 --> 00:24:35,840 +the user perceives as a document. + +625 +00:24:35,840 --> 00:24:37,760 +For example, your EmojiArtDocuments + +626 +00:24:37,760 --> 00:24:39,110 +would definitely be stored here. + +627 +00:24:39,110 --> 00:24:40,380 +If you didn't store them in iCloud, + +628 +00:24:40,380 --> 00:24:41,840 +you would definitely store them here, + +629 +00:24:41,840 --> 00:24:44,420 +but something like the emoji palette, + +630 +00:24:44,420 --> 00:24:46,460 +or maybe your Memorize themes even, + +631 +00:24:46,460 --> 00:24:47,757 +you probably would not store here. + +632 +00:24:47,757 --> 00:24:51,330 +The user does not like +perceive them as documents. + +633 +00:24:51,330 --> 00:24:53,030 +Though, those things will be stored + +634 +00:24:53,030 --> 00:24:54,910 +in the Application Support directory, + +635 +00:24:54,910 --> 00:24:56,930 +that's another directory. + +636 +00:24:56,930 --> 00:25:00,800 +Gets backed up by iCloud, it's permanent, + +637 +00:25:00,800 --> 00:25:03,980 +but the user doesn't see +them as documents in there, + +638 +00:25:03,980 --> 00:25:06,190 +kind of data that the user is creating + +639 +00:25:06,190 --> 00:25:08,090 +but not really document-oriented, + +640 +00:25:08,090 --> 00:25:08,923 +a subtle distinction there, + +641 +00:25:08,923 --> 00:25:11,500 +and it really doesn't matter too much + +642 +00:25:11,500 --> 00:25:13,020 +what how you do that unless you're using + +643 +00:25:13,020 --> 00:25:15,750 +the UIDocument stuff, +you're using UIDocument + +644 +00:25:15,750 --> 00:25:17,470 +that I mentioned earlier, +then, you definitely + +645 +00:25:17,470 --> 00:25:19,320 +want those documents +and only those documents + +646 +00:25:19,320 --> 00:25:20,410 +going in the Document structure. + +647 +00:25:20,410 --> 00:25:22,430 +You don't wanna put those in Applications + +648 +00:25:22,430 --> 00:25:24,560 +nor would you want to +put Application Support + +649 +00:25:24,560 --> 00:25:25,810 +stuff in the Document structure, + +650 +00:25:25,810 --> 00:25:29,390 +and confusing the user +about what's in there. + +651 +00:25:29,390 --> 00:25:31,180 +And there's a Caches directory. + +652 +00:25:31,180 --> 00:25:32,650 +This is temporary storage, + +653 +00:25:32,650 --> 00:25:34,210 +so this is storage that does not get + +654 +00:25:34,210 --> 00:25:37,910 +backed up into iCloud, and +if you deleted your sandbox, + +655 +00:25:37,910 --> 00:25:38,770 +it's gone forever. + +656 +00:25:38,770 --> 00:25:40,050 +So this would be things that you can + +657 +00:25:40,050 --> 00:25:42,730 +like easily get from the internet again, + +658 +00:25:42,730 --> 00:25:45,000 +images that you're just caching locally + +659 +00:25:45,000 --> 00:25:46,500 +for good performance. + +660 +00:25:46,500 --> 00:25:50,230 +But if you had to throw +away the Caches directory, + +661 +00:25:50,230 --> 00:25:51,861 +you could, and your app would still work + +662 +00:25:51,861 --> 00:25:53,500 +because it would just re-download + +663 +00:25:53,500 --> 00:25:57,050 +whatever needed from +that Caches directory. + +664 +00:25:57,050 --> 00:25:59,870 +If the iOS's disk started to get full, + +665 +00:25:59,870 --> 00:26:02,120 +it the iOS might start hunting around, + +666 +00:26:02,120 --> 00:26:04,530 +looking for Caches +directories and sandboxes + +667 +00:26:04,530 --> 00:26:06,660 +that are really big, that it can blast + +668 +00:26:06,660 --> 00:26:08,790 +to get space back too. + +669 +00:26:08,790 --> 00:26:10,890 +Rarely happens, most people's iOS devices + +670 +00:26:10,890 --> 00:26:14,020 +do not get full disks, but could happen. + +671 +00:26:14,020 --> 00:26:15,400 +And there's other directories, + +672 +00:26:15,400 --> 00:26:18,390 +which you can look in +the documentation for. + +673 +00:26:18,390 --> 00:26:22,330 +And let's talk about how we find out + +674 +00:26:22,330 --> 00:26:26,060 +what these directories +are inside of our app, + +675 +00:26:26,060 --> 00:26:28,370 +and we're gonna do that using something + +676 +00:26:28,370 --> 00:26:30,013 +called the FileManager. + +677 +00:26:30,013 --> 00:26:33,090 +The FileManager is an object, a struct, + +678 +00:26:33,090 --> 00:26:35,400 +that lets you, as its name implies, + +679 +00:26:35,400 --> 00:26:37,090 +manage the files in your file system, + +680 +00:26:37,090 --> 00:26:40,370 +including finding out where +these special directories are. + +681 +00:26:40,370 --> 00:26:43,140 +Now, there's two different +methods for doing this. + +682 +00:26:43,140 --> 00:26:46,530 +I'm giving you here a +little more complicated one. + +683 +00:26:46,530 --> 00:26:48,060 +There's a slightly simpler one + +684 +00:26:48,060 --> 00:26:50,180 +which is called URLs. + +685 +00:26:50,180 --> 00:26:51,520 +This one is called URL. + +686 +00:26:51,520 --> 00:26:54,640 +I'll use the simpler one in the demo, + +687 +00:26:54,640 --> 00:26:56,660 +so you'll get to see them both. + +688 +00:26:56,660 --> 00:26:59,680 +So this FileManager, how +do we use a FileManager? + +689 +00:26:59,680 --> 00:27:03,010 +Most of the time, if we're +working on the main queue, + +690 +00:27:03,010 --> 00:27:05,080 +which we are, most file operations + +691 +00:27:05,080 --> 00:27:07,820 +happen quick unless we're +writing a gigantic file. + +692 +00:27:07,820 --> 00:27:09,300 +So we can do them on the main queue. + +693 +00:27:09,300 --> 00:27:10,133 +They're not gonna block + +694 +00:27:10,133 --> 00:27:12,130 +like a network operation would. + +695 +00:27:12,130 --> 00:27:15,360 +We get this usually FileManager default, + +696 +00:27:15,360 --> 00:27:18,090 +FileManager.default, +which is the shared one. + +697 +00:27:18,090 --> 00:27:19,900 +Now, we probably wouldn't wanna use + +698 +00:27:19,900 --> 00:27:21,430 +that one off the main queue. + +699 +00:27:21,430 --> 00:27:22,490 +There, you'd want to create your + +700 +00:27:22,490 --> 00:27:24,700 +own instance of FileManager, + +701 +00:27:24,700 --> 00:27:26,920 +again, kind of an advanced topic. + +702 +00:27:26,920 --> 00:27:28,340 +So we just are gonna use the shared one + +703 +00:27:28,340 --> 00:27:30,830 +in the main queue and the function + +704 +00:27:30,830 --> 00:27:34,740 +that we're gonna call on this +shared.FileManager.default + +705 +00:27:34,740 --> 00:27:38,327 +thing is called url for +directory in domainMask, + +706 +00:27:38,327 --> 00:27:40,730 +and it's got these other things +appropriateFor and create. + +707 +00:27:40,730 --> 00:27:44,140 +So what are the four arguments +here to this URL thing? + +708 +00:27:44,140 --> 00:27:45,360 +The first one is which of + +709 +00:27:45,360 --> 00:27:47,150 +the special directories you want? + +710 +00:27:47,150 --> 00:27:51,180 +So this is an enum, +FileManager.SearchPathDirectory. + +711 +00:27:51,180 --> 00:27:52,420 +Go look in the documentation, + +712 +00:27:52,420 --> 00:27:54,590 +and you will see, I think there's 12 + +713 +00:27:54,590 --> 00:27:56,730 +or 15 different special directories + +714 +00:27:56,730 --> 00:27:59,290 +inside your sandboxes, like +the Document directory, + +715 +00:27:59,290 --> 00:28:00,540 +Applications, Support, Caches, + +716 +00:28:00,540 --> 00:28:01,580 +all the things we talked about, + +717 +00:28:01,580 --> 00:28:04,720 +there is an enum value for each of those. + +718 +00:28:04,720 --> 00:28:07,640 +The second argument is +in domainMask, in iOS, + +719 +00:28:07,640 --> 00:28:10,170 +this is always .userDomainMask, + +720 +00:28:10,170 --> 00:28:13,810 +because on a Mac, we might +have the network domain, + +721 +00:28:13,810 --> 00:28:16,399 +a shared library we're looking at. + +722 +00:28:16,399 --> 00:28:18,380 +But it on an iOS device, +it's a personal device, + +723 +00:28:18,380 --> 00:28:20,680 +so it's always userDomainMask. + +724 +00:28:20,680 --> 00:28:22,463 +Don't worry about appropriateFor, create. + +725 +00:28:24,610 --> 00:28:26,890 +If you're writing to +the Documents directory + +726 +00:28:26,890 --> 00:28:28,430 +for the first time, for example, + +727 +00:28:28,430 --> 00:28:29,410 +you would want to create it, + +728 +00:28:29,410 --> 00:28:32,100 +so you probably are gonna put create true, + +729 +00:28:32,100 --> 00:28:33,423 +when you do this. + +730 +00:28:34,590 --> 00:28:36,127 +And that's gonna return for you, + +731 +00:28:36,127 --> 00:28:38,710 +the URL to these special directories. + +732 +00:28:38,710 --> 00:28:40,810 +So now, that you have the +URL to the special directory + +733 +00:28:40,810 --> 00:28:42,710 +in the sandbox, you can start creating + +734 +00:28:42,710 --> 00:28:43,993 +or looking for files in there. + +735 +00:28:43,993 --> 00:28:45,650 +Now, how do we do that? + +736 +00:28:45,650 --> 00:28:48,860 +We do that with the methods in URL. + +737 +00:28:48,860 --> 00:28:50,740 +So we got this base URL, + +738 +00:28:50,740 --> 00:28:52,570 +and we're gonna use methods in URL + +739 +00:28:52,570 --> 00:28:54,452 +like appendingPathComponent, + +740 +00:28:54,452 --> 00:28:58,070 +and appendingPathExtension to build a path + +741 +00:28:58,070 --> 00:29:00,730 +to whatever file we're looking for + +742 +00:29:00,730 --> 00:29:05,210 +inside these special +directories, simple as that. + +743 +00:29:05,210 --> 00:29:07,727 +You can also ask the URL, things like, + +744 +00:29:07,727 --> 00:29:09,817 +"Is this the URL of a file + +745 +00:29:09,817 --> 00:29:13,300 +"versus the URL of a +network thing or web page?" + +746 +00:29:13,300 --> 00:29:14,847 +And you can ask the URL, + +747 +00:29:14,847 --> 00:29:18,130 +"Give me values for certain +resources in this file," + +748 +00:29:18,130 --> 00:29:20,090 +like its creation date, + +749 +00:29:20,090 --> 00:29:22,130 +or whether it's a directory or not, + +750 +00:29:22,130 --> 00:29:24,460 +or how big this file is. + +751 +00:29:24,460 --> 00:29:27,150 +And the API for this, again, pre-Swift, + +752 +00:29:27,150 --> 00:29:28,940 +not that weird, except for that + +753 +00:29:28,940 --> 00:29:31,450 +you give it the keys of what values + +754 +00:29:31,450 --> 00:29:32,750 +you want about this URL, + +755 +00:29:32,750 --> 00:29:34,860 +like its creation date, +or file size, or whatever, + +756 +00:29:34,860 --> 00:29:36,780 +and it gives you back a dictionary, + +757 +00:29:36,780 --> 00:29:38,810 +where those keys that you gave it + +758 +00:29:38,810 --> 00:29:41,160 +are the keys and the values are in Any. + +759 +00:29:41,160 --> 00:29:43,430 +And the reason value +has to be in Any there + +760 +00:29:43,430 --> 00:29:44,930 +because it could be a Date, + +761 +00:29:44,930 --> 00:29:47,970 +could be a file size, +would probably be an Int, + +762 +00:29:47,970 --> 00:29:49,790 +those kind of things. + +763 +00:29:49,790 --> 00:29:51,700 +So that's how you find out about URL. + +764 +00:29:51,700 --> 00:29:54,360 +So URL is an important part of interacting + +765 +00:29:54,360 --> 00:29:57,113 +with the file system, +just like FileManager is. + +766 +00:29:58,089 --> 00:30:00,730 +Another important struct is Data. + +767 +00:30:00,730 --> 00:30:02,180 +Data is how we actually + +768 +00:30:02,180 --> 00:30:03,957 +put the data out on the file system, + +769 +00:30:03,957 --> 00:30:06,860 +and you already know how to read data + +770 +00:30:06,860 --> 00:30:09,160 +from the internet using +Data's contentsOf URL. + +771 +00:30:11,339 --> 00:30:13,070 +And you can do the same +thing with a file URL, + +772 +00:30:13,070 --> 00:30:15,700 +so that's how you read +files off your disk, + +773 +00:30:15,700 --> 00:30:17,880 +out of your file system is with Data. + +774 +00:30:17,880 --> 00:30:19,270 +And oh, same thing with writing. + +775 +00:30:19,270 --> 00:30:20,503 +There's a write(to url: URL, ...), + +776 +00:30:21,409 --> 00:30:22,857 +and you just send it to a Data, + +777 +00:30:22,857 --> 00:30:26,930 +and it puts the contents +of itself into that URL, + +778 +00:30:26,930 --> 00:30:28,400 +in the file system. + +779 +00:30:28,400 --> 00:30:31,160 +Both of these have little +reading and writing options. + +780 +00:30:31,160 --> 00:30:34,450 +The writing ones are the +only ones that are very + +781 +00:30:34,450 --> 00:30:36,600 +interesting. For example, +there's write atomically. + +782 +00:30:36,600 --> 00:30:38,430 +So if you're writing a gigantic file, + +783 +00:30:38,430 --> 00:30:40,980 +and let's say the disk +fills up halfway through, + +784 +00:30:40,980 --> 00:30:43,670 +the file will now not +be in a corrupted state + +785 +00:30:43,670 --> 00:30:45,810 +halfway written, it'll just revert back + +786 +00:30:45,810 --> 00:30:48,553 +to the state it was before +you tried to do this write. + +787 +00:30:48,553 --> 00:30:50,120 +So that's an atomic transaction. + +788 +00:30:50,120 --> 00:30:52,150 +Like essentially, it +writes to a temporary file. + +789 +00:30:52,150 --> 00:30:54,280 +If that's successful, then, it'll move it + +790 +00:30:54,280 --> 00:30:57,023 +into the URL you're trying to write to. + +791 +00:30:59,120 --> 00:31:01,660 +FileManager can also potentially help you + +792 +00:31:01,660 --> 00:31:03,810 +understand what's going +on in the file system, + +793 +00:31:03,810 --> 00:31:06,240 +similar to what URL was doing. + +794 +00:31:06,240 --> 00:31:07,780 +And it also can do things like, + +795 +00:31:07,780 --> 00:31:10,630 +show me all the files that +are in this directory, + +796 +00:31:10,630 --> 00:31:13,990 +or move this file from +this URL to this one, + +797 +00:31:13,990 --> 00:31:17,350 +or copy this file, make +a copy of this URL. + +798 +00:31:17,350 --> 00:31:20,130 +And I'm gonna show, instead +of going through slides, + +799 +00:31:20,130 --> 00:31:21,240 +and showing you all the things + +800 +00:31:21,240 --> 00:31:22,460 +that a FileManager can do, first of all, + +801 +00:31:22,460 --> 00:31:24,540 +you can just look at the documentation, + +802 +00:31:24,540 --> 00:31:26,130 +but I'm actually gonna show you + +803 +00:31:26,130 --> 00:31:27,860 +in a demo in here in a moment. + +804 +00:31:27,860 --> 00:31:30,170 +One thing I wanna note about FileManager, + +805 +00:31:30,170 --> 00:31:32,260 +it has something called a delegate. + +806 +00:31:32,260 --> 00:31:34,610 +Delegate is just a var on it. + +807 +00:31:34,610 --> 00:31:37,800 +And that var is an object that you set, + +808 +00:31:37,800 --> 00:31:39,800 +and that object will be notified + +809 +00:31:39,800 --> 00:31:41,450 +when certain things are happening + +810 +00:31:41,450 --> 00:31:42,520 +in the FileManager. + +811 +00:31:42,520 --> 00:31:44,780 +As a FileManager goes around, moves files, + +812 +00:31:44,780 --> 00:31:49,490 +tries to do things, it's +going to talk to its delegate, + +813 +00:31:49,490 --> 00:31:50,540 +and ask you to do things. + +814 +00:31:50,540 --> 00:31:54,140 +Now, this delegate stuff, +fundamental to UIKit. + +815 +00:31:54,140 --> 00:31:55,910 +Everywhere in UIKit, there's delegates, + +816 +00:31:55,910 --> 00:31:58,243 +and we'll see that in our next lecture, + +817 +00:31:58,243 --> 00:31:59,490 +because we're gonna +start talking about UIKit + +818 +00:31:59,490 --> 00:32:02,130 +integration with SwiftUI. + +819 +00:32:02,130 --> 00:32:04,070 +But if you're looking at FileManager, + +820 +00:32:04,070 --> 00:32:05,807 +you're probably like, "What +is this delegate thing? + +821 +00:32:05,807 --> 00:32:07,260 +"Never seen it before." + +822 +00:32:07,260 --> 00:32:09,890 +And I don't think you need +a FileManager's delegate + +823 +00:32:09,890 --> 00:32:12,200 +to do most stuff in FileManager. + +824 +00:32:12,200 --> 00:32:14,400 +We're going to do our demo, + +825 +00:32:14,400 --> 00:32:16,330 +and never even set the delegate, + +826 +00:32:16,330 --> 00:32:17,867 +but I just don't want +you to be surprised by, + +827 +00:32:17,867 --> 00:32:19,370 +"Oh, what's this delegate thing?" + +828 +00:32:19,370 --> 00:32:20,430 +It's essentially just an object + +829 +00:32:20,430 --> 00:32:22,130 +that gets notified when +things are happening + +830 +00:32:22,130 --> 00:32:24,023 +during FileManager operations. + +831 +00:32:25,160 --> 00:32:27,180 +All right, so a demo is +worth a thousand words. + +832 +00:32:27,180 --> 00:32:29,270 +As we always say, thousands of words. + +833 +00:32:29,270 --> 00:32:31,230 +So let's check it out. + +834 +00:32:31,230 --> 00:32:32,690 +What we're gonna do in our demo today + +835 +00:32:32,690 --> 00:32:36,950 +is store our EmojiArtDocuments +into the file system + +836 +00:32:36,950 --> 00:32:38,990 +instead of UserDefaults, which was silly, + +837 +00:32:38,990 --> 00:32:40,400 +that was demo-ware. + +838 +00:32:40,400 --> 00:32:42,580 +Storing in the file system +makes a lot more sense. + +839 +00:32:42,580 --> 00:32:45,640 +Storing them in iCloud would +make even more sense than that. + +840 +00:32:45,640 --> 00:32:47,714 +But we will store them in there, + +841 +00:32:47,714 --> 00:32:48,830 +and this is gonna be able to show us + +842 +00:32:48,830 --> 00:32:50,393 +all parts of accessing the file system + +843 +00:32:50,393 --> 00:32:52,710 +because we're gonna have to get a URL + +844 +00:32:52,710 --> 00:32:54,610 +to our Documents directory, + +845 +00:32:54,610 --> 00:32:57,130 +so we're gonna be using URL to do that, + +846 +00:32:57,130 --> 00:32:59,150 +and FileManager to do that. + +847 +00:32:59,150 --> 00:33:01,170 +Then, we're gonna write +our data out, of course, + +848 +00:33:01,170 --> 00:33:03,040 +using the Data object. + +849 +00:33:03,040 --> 00:33:06,770 +And then, I'm also going to +make my DocumentChooser work, + +850 +00:33:06,770 --> 00:33:09,850 +so removing documents, +adding new documents, + +851 +00:33:09,850 --> 00:33:11,820 +are going to have to work. + +852 +00:33:11,820 --> 00:33:13,790 +And so, we'll have to +be using the FileManager + +853 +00:33:13,790 --> 00:33:15,325 +to do some file system operations + +854 +00:33:15,325 --> 00:33:17,863 +to make that stuff work as well. + +855 +00:33:18,830 --> 00:33:21,393 +So let's dive into that demo right now. + +856 +00:33:23,530 --> 00:33:26,670 +So the goal of this demo is to make + +857 +00:33:26,670 --> 00:33:31,660 +EmojiArtDocumentStore stop storing itself, + +858 +00:33:31,660 --> 00:33:33,823 +right here, and EmojiArtDocuments, + +859 +00:33:35,770 --> 00:33:38,450 +over here, in UserDefaults. + +860 +00:33:38,450 --> 00:33:40,470 +Instead we want them to store + +861 +00:33:40,470 --> 00:33:44,073 +in the Unix file system +that underlies iOS. + +862 +00:33:44,980 --> 00:33:46,790 +So it's really two things we have to fix. + +863 +00:33:46,790 --> 00:33:49,330 +We have to get documents to +be storing in the file system, + +864 +00:33:49,330 --> 00:33:51,600 +and we have to get the DocumentStore + +865 +00:33:51,600 --> 00:33:53,120 +to be looking in the file system + +866 +00:33:53,120 --> 00:33:55,520 +instead of looking in UserDefaults. + +867 +00:33:55,520 --> 00:33:57,500 +Let's start with the Document here, + +868 +00:33:57,500 --> 00:34:00,770 +and I'm gonna add this +capability to the Store + +869 +00:34:00,770 --> 00:34:03,380 +and to the Document to +work in the file system, + +870 +00:34:03,380 --> 00:34:06,370 +and leave this UserDefaults capability, + +871 +00:34:06,370 --> 00:34:08,470 +in case someone wants that instead. + +872 +00:34:08,470 --> 00:34:11,313 +There's no reason to +break what we had before. + +873 +00:34:12,600 --> 00:34:15,230 +So creating an EmojiArtDocument here + +874 +00:34:15,230 --> 00:34:17,730 +that stores itself in the file system, + +875 +00:34:17,730 --> 00:34:19,150 +it's just gonna be for me, + +876 +00:34:19,150 --> 00:34:21,360 +a matter of a different init. + +877 +00:34:21,360 --> 00:34:23,617 +So this init takes a UUID, + +878 +00:34:23,617 --> 00:34:26,650 +and which it uses to store in default. + +879 +00:34:26,650 --> 00:34:31,160 +I'm gonna have my init, +instead of that, take a URL. + +880 +00:34:31,160 --> 00:34:32,980 +And this is gonna be the URL + +881 +00:34:32,980 --> 00:34:35,130 +to use to read the Document + +882 +00:34:35,130 --> 00:34:36,800 +from the file system initially, + +883 +00:34:36,800 --> 00:34:38,480 +and then, also to save the Document + +884 +00:34:38,480 --> 00:34:40,110 +anytime we want to autosave, + +885 +00:34:40,110 --> 00:34:42,760 +we're gonna use this URL for that. + +886 +00:34:42,760 --> 00:34:45,090 +We're still gonna need to set our id + +887 +00:34:45,090 --> 00:34:48,600 +to be some UUID because this id + +888 +00:34:48,600 --> 00:34:50,950 +is part of our Identifiable, right? + +889 +00:34:50,950 --> 00:34:52,860 +So we still need to do that. + +890 +00:34:52,860 --> 00:34:55,310 +But in here, we're going to also grab + +891 +00:34:55,310 --> 00:35:00,033 +a hold of this URL and +put it in a little var. + +892 +00:35:01,000 --> 00:35:04,180 +We're gonna use this URL +to load this thing up + +893 +00:35:04,180 --> 00:35:06,120 +and to autosave, so let's start + +894 +00:35:06,120 --> 00:35:08,270 +with the loading of it up. + +895 +00:35:08,270 --> 00:35:09,730 +It's pretty straightforward here actually. + +896 +00:35:09,730 --> 00:35:14,730 +We already know how to load +up an EmojiArt from a URL, + +897 +00:35:14,990 --> 00:35:17,217 +because we know how to +get a Data from the URL, + +898 +00:35:17,217 --> 00:35:20,380 +and we know how to load +an EmojiArt from Data. + +899 +00:35:20,380 --> 00:35:22,937 +So let's just do EmojiArt here, + +900 +00:35:22,937 --> 00:35:24,810 +and we're gonna pass it some JSON, + +901 +00:35:24,810 --> 00:35:29,810 +which is trying to get +the contents of this URL + +902 +00:35:31,080 --> 00:35:33,230 +from the file system, +and if we can't do that, + +903 +00:35:33,230 --> 00:35:36,150 +by the way, let's just +do a blank EmojiArt, + +904 +00:35:36,150 --> 00:35:38,400 +because maybe, they gave us the URL + +905 +00:35:38,400 --> 00:35:39,770 +that they want us to save to + +906 +00:35:39,770 --> 00:35:42,690 +but there's no such file +currently in existence, + +907 +00:35:42,690 --> 00:35:44,440 +and so we'll create a blank file for them. + +908 +00:35:44,440 --> 00:35:47,150 +So it's the same data contentsOf + +909 +00:35:47,150 --> 00:35:49,370 +that we were using when we fetched + +910 +00:35:49,370 --> 00:35:50,670 +things over the internet, + +911 +00:35:50,670 --> 00:35:53,783 +we're just using it now with a file URL. + +912 +00:35:55,160 --> 00:35:57,700 +Oh, we still want to fetch the background + +913 +00:35:57,700 --> 00:36:02,390 +image data here from that, +whatever that's coming from. + +914 +00:36:02,390 --> 00:36:05,520 +And we still want to do +autosaveCancellable up here. + +915 +00:36:05,520 --> 00:36:06,480 +But of course, we're not going + +916 +00:36:06,480 --> 00:36:08,750 +to autosave into UserDefaults. + +917 +00:36:08,750 --> 00:36:10,800 +This time, we're gonna do +our autosaveCancellable + +918 +00:36:12,430 --> 00:36:14,623 +to sync off of our EmojiArt. + +919 +00:36:16,860 --> 00:36:19,270 +For this autosave, we want to essentially + +920 +00:36:19,270 --> 00:36:23,770 +save our EmojiArt, have a +little function to do that, + +921 +00:36:23,770 --> 00:36:27,793 +little private func save, which +takes an EmojiArt to save. + +922 +00:36:29,430 --> 00:36:32,610 +And all this is going +to do is do the kind of + +923 +00:36:32,610 --> 00:36:35,810 +the inverse of what we did +right here with this Data. + +924 +00:36:35,810 --> 00:36:39,730 +We're going to say, if our URL is not nil, + +925 +00:36:39,730 --> 00:36:42,550 +in other words, we're the +kind of EmojiArtDocument + +926 +00:36:42,550 --> 00:36:45,000 +that saves to the file system, + +927 +00:36:45,000 --> 00:36:49,340 +then, we're gonna try to +have our EmojiArt's json + +928 +00:36:49,340 --> 00:36:52,733 +write itself to our URL. + +929 +00:36:53,780 --> 00:36:55,953 +One liner here to write ourselves out. + +930 +00:36:57,050 --> 00:36:59,720 +Now, one other thing +I'm thinking I might do + +931 +00:36:59,720 --> 00:37:02,703 +is here, I'm autosaving +every time it changes. + +932 +00:37:03,620 --> 00:37:06,270 +What if somebody changes this URL on me? + +933 +00:37:06,270 --> 00:37:09,466 +So, my Document was +writing out to some URL, + +934 +00:37:09,466 --> 00:37:12,010 +and autosaving, and then, +they change this URL. + +935 +00:37:12,010 --> 00:37:13,750 +Well, the next time I autosave, + +936 +00:37:13,750 --> 00:37:15,930 +that's okay, it'll write to this URL. + +937 +00:37:15,930 --> 00:37:18,560 +But I'm gonna be a little +more immediate than that. + +938 +00:37:18,560 --> 00:37:21,090 +I'm gonna put a didSet in here, + +939 +00:37:21,090 --> 00:37:25,740 +which does save of my own EmojiArt, + +940 +00:37:25,740 --> 00:37:29,390 +just to immediately save to a new URL + +941 +00:37:29,390 --> 00:37:31,410 +if somebody sets it on me. + +942 +00:37:31,410 --> 00:37:35,050 +Probably not critical but I think + +943 +00:37:35,050 --> 00:37:38,050 +if someone sets a new URL on my document, + +944 +00:37:38,050 --> 00:37:39,820 +they probably want it to pretty + +945 +00:37:39,820 --> 00:37:41,260 +quickly write that thing out, + +946 +00:37:41,260 --> 00:37:42,650 +they don't want to rely on the user + +947 +00:37:42,650 --> 00:37:44,830 +having to add an emoji or something + +948 +00:37:44,830 --> 00:37:46,400 +to cause an autosave done. + +949 +00:37:48,011 --> 00:37:50,440 +And this is it, it's +really all that's required + +950 +00:37:50,440 --> 00:37:52,770 +to get our EmojiArt to write itself + +951 +00:37:52,770 --> 00:37:55,373 +into a URL, quite straightforward. + +952 +00:37:56,320 --> 00:37:59,540 +Now, the other piece of this whole puzzle + +953 +00:37:59,540 --> 00:38:01,020 +is back in our store right here, + +954 +00:38:01,020 --> 00:38:04,020 +because right now, our +store keeps the names + +955 +00:38:04,020 --> 00:38:06,640 +of all the documents in +a little Dictionary here, + +956 +00:38:06,640 --> 00:38:09,657 +which is reading and +writing from UserDefaults, + +957 +00:38:09,657 --> 00:38:14,390 +and we want these names to +come out of the file system. + +958 +00:38:14,390 --> 00:38:18,490 +So we wanted to look into a +URL of a directory somewhere, + +959 +00:38:18,490 --> 00:38:20,137 +look at all the files that are in there, + +960 +00:38:20,137 --> 00:38:23,140 +and use those as the +names of all the documents + +961 +00:38:23,140 --> 00:38:24,640 +that are in there. + +962 +00:38:24,640 --> 00:38:26,360 +So this also is something we can do + +963 +00:38:26,360 --> 00:38:30,000 +without breaking our existing init named, + +964 +00:38:30,000 --> 00:38:32,710 +where it's going and +looking in UserDefaults. + +965 +00:38:32,710 --> 00:38:34,750 +For this, we can just do a new init. + +966 +00:38:34,750 --> 00:38:38,660 +And this init is going +to take a directory, + +967 +00:38:38,660 --> 00:38:41,110 +which is just gonna be a URL. + +968 +00:38:41,110 --> 00:38:42,950 +And we're gonna look in this directory, + +969 +00:38:42,950 --> 00:38:44,600 +and load up our documentNames, + +970 +00:38:44,600 --> 00:38:47,943 +whatever files, with whatever +files we find in here. + +971 +00:38:49,340 --> 00:38:50,840 +Now, what's gonna be our name? + +972 +00:38:50,840 --> 00:38:52,970 +You remember our Store has a name here, + +973 +00:38:52,970 --> 00:38:55,070 +where init with name so +we're providing the name, + +974 +00:38:55,070 --> 00:38:56,840 +this is the name of the Store itself, + +975 +00:38:56,840 --> 00:38:58,380 +not the names of any Documents, + +976 +00:38:58,380 --> 00:39:00,260 +just the name of the Store itself. + +977 +00:39:00,260 --> 00:39:02,770 +We could have that be +an argument here as well + +978 +00:39:02,770 --> 00:39:05,350 +or another argument name but for fun, + +979 +00:39:05,350 --> 00:39:07,520 +I'm gonna set our name here + +980 +00:39:07,520 --> 00:39:12,053 +to be equal to our +directory's lastPathComponent. + +981 +00:39:12,960 --> 00:39:14,880 +Now, this might not really be good + +982 +00:39:14,880 --> 00:39:17,530 +because maybe this is +an internal directory + +983 +00:39:17,530 --> 00:39:18,520 +that stores our documents. + +984 +00:39:18,520 --> 00:39:19,920 +So I'm gonna make this eventually + +985 +00:39:19,920 --> 00:39:21,880 +be our Documents directory. + +986 +00:39:21,880 --> 00:39:22,783 +So this is gonna look pretty good + +987 +00:39:22,783 --> 00:39:25,270 +because I think that's called Documents, + +988 +00:39:25,270 --> 00:39:28,070 +but I mostly wanted to do this to show you + +989 +00:39:28,070 --> 00:39:30,940 +what it looks like to grab +the last component out + +990 +00:39:30,940 --> 00:39:34,390 +and put it in something that +we're gonna see in the UI. + +991 +00:39:34,390 --> 00:39:36,240 +But, in reality, probably want another + +992 +00:39:36,240 --> 00:39:37,723 +argument there for the name. + +993 +00:39:38,830 --> 00:39:41,040 +And so we're gonna grab +onto this directory. + +994 +00:39:41,040 --> 00:39:45,890 +So let's say self.directory +equals this directory, + +995 +00:39:45,890 --> 00:39:49,823 +put that into a little +private var directory, + +996 +00:39:50,780 --> 00:39:51,973 +which is a URL. + +997 +00:39:53,140 --> 00:39:54,720 +So this URL, and this directory + +998 +00:39:54,720 --> 00:39:57,730 +points us to where all of +our Documents are stored. + +999 +00:39:57,730 --> 00:40:01,780 +We're obviously gonna wanna +create this DocumentStore + +1000 +00:40:01,780 --> 00:40:06,310 +likely with our Documents +directory in our sandbox. + +1001 +00:40:06,310 --> 00:40:07,950 +But we'll get that a little bit. + +1002 +00:40:07,950 --> 00:40:09,440 +Right now, we're gonna +make this DocumentStore + +1003 +00:40:09,440 --> 00:40:12,540 +so it can work with +any directory anywhere. + +1004 +00:40:12,540 --> 00:40:15,070 +You pass what directory +you want to its init, + +1005 +00:40:15,070 --> 00:40:16,900 +and it's just going to open it up, + +1006 +00:40:16,900 --> 00:40:19,113 +and look at all the +files that are in there. + +1007 +00:40:19,980 --> 00:40:22,240 +Now, how does it open it up, + +1008 +00:40:22,240 --> 00:40:23,690 +and look at all the +files that are in there? + +1009 +00:40:23,690 --> 00:40:26,230 +How do we find out what +files are in the directory? + +1010 +00:40:26,230 --> 00:40:29,077 +Well, we're gonna use +that FileManager thing, + +1011 +00:40:29,077 --> 00:40:31,610 +and it's got a really +cool little function. + +1012 +00:40:31,610 --> 00:40:33,770 +I'm gonna call this documents, + +1013 +00:40:33,770 --> 00:40:38,500 +let documents equal FileManager.default, + +1014 +00:40:38,500 --> 00:40:40,000 +that's the shared one. + +1015 +00:40:40,000 --> 00:40:43,020 +Give me the contentsOfDirectory. + +1016 +00:40:43,020 --> 00:40:44,700 +You can see there's a +couple of them right here. + +1017 +00:40:44,700 --> 00:40:47,600 +I want this one, directory atPath, + +1018 +00:40:47,600 --> 00:40:51,660 +my directory's path, directory.path. + +1019 +00:40:51,660 --> 00:40:56,430 +Path right here is a URL +method or var, actually, + +1020 +00:40:56,430 --> 00:41:00,770 +and this var returns this URL as a String. + +1021 +00:41:00,770 --> 00:41:03,010 +And that's a lot of the FileManager things + +1022 +00:41:03,010 --> 00:41:04,840 +take these paths as Strings, + +1023 +00:41:04,840 --> 00:41:07,875 +some of them take URLs, +but some can take Strings. + +1024 +00:41:07,875 --> 00:41:09,490 +This one happens to be convenient + +1025 +00:41:09,490 --> 00:41:12,623 +because it just takes this +nice one argument right here. + +1026 +00:41:13,683 --> 00:41:14,750 +Now, you can see we have an error, + +1027 +00:41:14,750 --> 00:41:17,420 +call can throw, but it's +not marked with try. + +1028 +00:41:17,420 --> 00:41:21,280 +So I could say try? here, + +1029 +00:41:21,280 --> 00:41:25,210 +but I'm gonna actually +do the do catch here + +1030 +00:41:25,210 --> 00:41:28,540 +because I want you to get a look at it + +1031 +00:41:28,540 --> 00:41:31,730 +every once in a while, so +that you know what's going on. + +1032 +00:41:31,730 --> 00:41:33,530 +Otherwise, I'll send +you out of this class, + +1033 +00:41:33,530 --> 00:41:35,790 +and you'll just always be doing try?, + +1034 +00:41:35,790 --> 00:41:37,430 +and you won't think about the fact + +1035 +00:41:37,430 --> 00:41:40,070 +that we can do try +without a question mark, + +1036 +00:41:40,070 --> 00:41:41,733 +and catch the error. + +1037 +00:41:42,760 --> 00:41:44,010 +I do this one other demo, + +1038 +00:41:44,010 --> 00:41:45,330 +and we'll do it again here. + +1039 +00:41:45,330 --> 00:41:46,393 +Now, I could just for now, + +1040 +00:41:46,393 --> 00:41:49,030 +I would just maybe print this error out, + +1041 +00:41:49,030 --> 00:41:54,030 +"EmojiArtDocumentStore couldn't +create store from directory" + +1042 +00:41:56,430 --> 00:41:58,720 +Let's print out the directory. + +1043 +00:41:58,720 --> 00:42:00,460 +That was attempted here, + +1044 +00:42:00,460 --> 00:42:03,360 +and we'll even print out the +error's localizedDescription. + +1045 +00:42:05,920 --> 00:42:07,750 +And we might want to, for example, + +1046 +00:42:07,750 --> 00:42:11,050 +make this be a failable +initializer perhaps, + +1047 +00:42:11,050 --> 00:42:14,050 +and then, return nil in here. + +1048 +00:42:14,050 --> 00:42:16,650 +So it's kind of how you do error handling. + +1049 +00:42:16,650 --> 00:42:18,700 +You really want to think in general, + +1050 +00:42:18,700 --> 00:42:20,410 +what your strategy is, + +1051 +00:42:20,410 --> 00:42:22,050 +are you gonna notify the user, + +1052 +00:42:22,050 --> 00:42:24,000 +are you gonna try and recover? + +1053 +00:42:24,000 --> 00:42:25,870 +I'm kind of a fan of trying to recover + +1054 +00:42:25,870 --> 00:42:27,690 +as much as possible but by the same token, + +1055 +00:42:27,690 --> 00:42:29,470 +you don't wanna mislead your user + +1056 +00:42:29,470 --> 00:42:31,140 +into thinking that somehow, + +1057 +00:42:31,140 --> 00:42:33,090 +something that they thought was working, + +1058 +00:42:33,090 --> 00:42:35,143 +did not work or vice versa. + +1059 +00:42:36,280 --> 00:42:37,660 +All right, so we've got our Documents. + +1060 +00:42:37,660 --> 00:42:39,870 +This is an array of Strings. + +1061 +00:42:39,870 --> 00:42:41,370 +If you look at it here, array of Strings. + +1062 +00:42:41,370 --> 00:42:43,010 +These Strings are just the names + +1063 +00:42:43,010 --> 00:42:45,515 +of all the files in this directory. + +1064 +00:42:45,515 --> 00:42:46,650 +Couldn't be simpler. + +1065 +00:42:46,650 --> 00:42:48,350 +So let's go through each of those. + +1066 +00:42:49,890 --> 00:42:52,160 +And for each one, I'm going to create + +1067 +00:42:52,160 --> 00:42:56,700 +an EmojiArtDocument from +what I find in that file, + +1068 +00:42:56,700 --> 00:42:59,020 +EmojiArtDocument, and it's great. + +1069 +00:42:59,020 --> 00:43:01,233 +We just added EmojiArtDocument URL. + +1070 +00:43:02,340 --> 00:43:05,430 +So how do I create a URL to this document? + +1071 +00:43:05,430 --> 00:43:06,680 +This document is a String, + +1072 +00:43:06,680 --> 00:43:08,377 +it's just the name of the file, + +1073 +00:43:08,377 --> 00:43:10,300 +and I have the directory right here, + +1074 +00:43:10,300 --> 00:43:12,380 +so I'm gonna take the directory, + +1075 +00:43:12,380 --> 00:43:15,963 +and I'm going to append a path component, + +1076 +00:43:17,400 --> 00:43:19,683 +which is that document name. + +1077 +00:43:20,610 --> 00:43:22,700 +So I'm just creating another URL here + +1078 +00:43:22,700 --> 00:43:25,000 +from our directory URL by adding + +1079 +00:43:25,000 --> 00:43:26,640 +the document name back in. + +1080 +00:43:26,640 --> 00:43:29,170 +And I'm doing this for +every one of the documents + +1081 +00:43:29,170 --> 00:43:31,910 +that I found in that +directory, super simple. + +1082 +00:43:31,910 --> 00:43:33,300 +When I have this document, + +1083 +00:43:33,300 --> 00:43:36,230 +I'm gonna add this to +my own documentNames, + +1084 +00:43:37,160 --> 00:43:42,160 +this EmojiArtDocument, +and its name is document. + +1085 +00:43:44,810 --> 00:43:47,700 +Now, we've updated our +internal data structure + +1086 +00:43:47,700 --> 00:43:49,247 +to reflect what's in the file system, + +1087 +00:43:49,247 --> 00:43:51,730 +and we've done this at initialize time. + +1088 +00:43:51,730 --> 00:43:54,070 +Now, we still have quite a +bit more work to do up here + +1089 +00:43:54,070 --> 00:43:56,000 +with all these adding, and removing, + +1090 +00:43:56,000 --> 00:43:57,500 +and changing names of documents. + +1091 +00:43:57,500 --> 00:44:00,400 +we're gonna have to keep the +file system in sync up there + +1092 +00:44:00,400 --> 00:44:03,650 +but at least we kinda got +started here on the right foot + +1093 +00:44:03,650 --> 00:44:05,760 +by having our internal data structure + +1094 +00:44:05,760 --> 00:44:07,413 +load up from the file system. + +1095 +00:44:08,710 --> 00:44:10,300 +That's pretty much all +is necessary to do that. + +1096 +00:44:10,300 --> 00:44:13,470 +So now, let's go back to our SceneDelegate + +1097 +00:44:13,470 --> 00:44:16,200 +over here, where we are +creating this DocumentStore + +1098 +00:44:16,200 --> 00:44:20,084 +called EmojiArt that we +get out of UserDefaults, + +1099 +00:44:20,084 --> 00:44:22,150 +and instead of doing that, let's go + +1100 +00:44:22,150 --> 00:44:27,047 +and let our store equal +an EmojiArtDocumentStore, + +1101 +00:44:29,160 --> 00:44:32,330 +whose directory is a URL, + +1102 +00:44:32,330 --> 00:44:35,990 +and this URL is going to +be our Documents directory + +1103 +00:44:35,990 --> 00:44:39,170 +in our sandbox, that special directory. + +1104 +00:44:39,170 --> 00:44:42,340 +Everybody remember from +the slides how we do that? + +1105 +00:44:42,340 --> 00:44:44,840 +Say let url =, again, + +1106 +00:44:44,840 --> 00:44:48,290 +we're gonna use the +FileManager, the shared one. + +1107 +00:44:48,290 --> 00:44:49,999 +In the slides, I showed you this one + +1108 +00:44:49,999 --> 00:44:53,470 +URL for SearchPathDirectory + +1109 +00:44:53,470 --> 00:44:55,533 +in appropriateFor create, remember that? + +1110 +00:44:55,533 --> 00:44:59,690 +When you said different one +here, it's called URLs, plural. + +1111 +00:44:59,690 --> 00:45:03,800 +And you still specify the +special directory you want. + +1112 +00:45:03,800 --> 00:45:07,470 +So I want the documentDirectory, +careful there. + +1113 +00:45:07,470 --> 00:45:09,770 +You don't want to do +documentationDirectory, + +1114 +00:45:09,770 --> 00:45:11,840 +you want documentDirectory. + +1115 +00:45:11,840 --> 00:45:12,960 +What's a documentDirectory? + +1116 +00:45:12,960 --> 00:45:16,600 +And we always again in userDomainMask, + +1117 +00:45:16,600 --> 00:45:20,190 +iOS is an operating system +for individual devices, + +1118 +00:45:20,190 --> 00:45:23,370 +so we're always giving the +user's Document directory, + +1119 +00:45:23,370 --> 00:45:25,070 +not the shared one on the network, + +1120 +00:45:25,070 --> 00:45:26,780 +or something like that. + +1121 +00:45:26,780 --> 00:45:30,690 +Now, this URL's version +returns an Array of them, + +1122 +00:45:30,690 --> 00:45:32,410 +again, because on other platforms, + +1123 +00:45:32,410 --> 00:45:35,570 +you might have multiple masks here, + +1124 +00:45:35,570 --> 00:45:37,540 +user mask, network mask, so you might + +1125 +00:45:37,540 --> 00:45:39,200 +be getting multiple responses. + +1126 +00:45:39,200 --> 00:45:41,860 +Here, we're only going to get one. + +1127 +00:45:41,860 --> 00:45:45,160 +And I'm gonna throw an +exclamation point on here + +1128 +00:45:45,160 --> 00:45:47,790 +in the assumption that I always + +1129 +00:45:47,790 --> 00:45:50,570 +have my documentDirectory here. + +1130 +00:45:50,570 --> 00:45:54,720 +And putting an exclamation point here, + +1131 +00:45:54,720 --> 00:45:56,930 +that's not true, and this crashes. + +1132 +00:45:56,930 --> 00:46:00,410 +I'm gonna at least find that +during my development period, + +1133 +00:46:00,410 --> 00:46:02,010 +but when it comes time to ship, + +1134 +00:46:02,010 --> 00:46:05,410 +maybe, I'll do something +where I use this kind of store + +1135 +00:46:05,410 --> 00:46:07,440 +if for some reason I can't, + +1136 +00:46:07,440 --> 00:46:10,110 +I don't have a documentDirectory. + +1137 +00:46:10,110 --> 00:46:11,848 +So, this is it. + +1138 +00:46:11,848 --> 00:46:13,300 +We've got the Store, let's run! + +1139 +00:46:13,300 --> 00:46:14,550 +See what's going on here. + +1140 +00:46:16,200 --> 00:46:19,410 +All right, so this is probably working + +1141 +00:46:19,410 --> 00:46:21,110 +because there's no documents here. + +1142 +00:46:21,110 --> 00:46:23,470 +See, we have no documents +in our file system, + +1143 +00:46:23,470 --> 00:46:26,400 +our documentDirectory in our +sandbox is probably empty. + +1144 +00:46:26,400 --> 00:46:27,960 +So all this well. + +1145 +00:46:27,960 --> 00:46:30,890 +Yeah, maybe we could +add some documents here, + +1146 +00:46:30,890 --> 00:46:33,870 +but this is not actually +adding them to the file system. + +1147 +00:46:33,870 --> 00:46:38,470 +If I stop and rerun, these documents, + +1148 +00:46:38,470 --> 00:46:40,923 +no change, of course, because +"+" is not doing anything, + +1149 +00:46:40,923 --> 00:46:45,220 +it's just adding it to our +little local documentName + +1150 +00:46:45,220 --> 00:46:49,100 +data structure here in our DocumentStore. + +1151 +00:46:49,100 --> 00:46:52,170 +And so this is having no +effect on the file system. + +1152 +00:46:52,170 --> 00:46:54,420 +So we need to update these things up here, + +1153 +00:46:54,420 --> 00:46:57,710 +addDocument, removeDocument, even setName, + +1154 +00:46:57,710 --> 00:46:59,800 +to affect the file system as well. + +1155 +00:46:59,800 --> 00:47:00,944 +And that's gonna be great + +1156 +00:47:00,944 --> 00:47:01,777 +because we're gonna get a chance + +1157 +00:47:01,777 --> 00:47:03,890 +to see how do we affect the file system. + +1158 +00:47:03,890 --> 00:47:07,500 +We already learned how to read +the contents of a directory. + +1159 +00:47:07,500 --> 00:47:09,300 +Now, let's learn how we, for example, + +1160 +00:47:09,300 --> 00:47:11,173 +remove files and things like that. + +1161 +00:47:12,110 --> 00:47:13,550 +So let's do addDocument first, + +1162 +00:47:13,550 --> 00:47:15,720 +so we can get some documents going + +1163 +00:47:15,720 --> 00:47:17,560 +in our documentDirectory here. + +1164 +00:47:17,560 --> 00:47:20,170 +And addDocument has a little bit + +1165 +00:47:20,170 --> 00:47:22,340 +of an interesting aspect to it + +1166 +00:47:22,340 --> 00:47:25,000 +when we start storing in the file system. + +1167 +00:47:25,000 --> 00:47:26,747 +When we store it in UserDefaults, + +1168 +00:47:26,747 --> 00:47:28,870 +we can have two, or +three, or four documents + +1169 +00:47:28,870 --> 00:47:30,815 +with exactly the same name. + +1170 +00:47:30,815 --> 00:47:32,060 +And that's perfectly fine. + +1171 +00:47:32,060 --> 00:47:34,250 +But in the file system, +that's not allowed. + +1172 +00:47:34,250 --> 00:47:36,860 +The file system, you only get one document + +1173 +00:47:36,860 --> 00:47:38,940 +of a certain file name. + +1174 +00:47:38,940 --> 00:47:40,460 +That's just the way it is. + +1175 +00:47:40,460 --> 00:47:41,710 +That's the way file systems work. + +1176 +00:47:41,710 --> 00:47:44,010 +We distinguish the +things in the file system + +1177 +00:47:44,010 --> 00:47:46,140 +by the name of the file. + +1178 +00:47:46,140 --> 00:47:48,800 +So I'm going to have to be careful here + +1179 +00:47:48,800 --> 00:47:51,650 +when if I'm dealing with the file system, + +1180 +00:47:51,650 --> 00:47:54,390 +to not just use the name +that's passed to me, + +1181 +00:47:54,390 --> 00:47:56,530 +or even just "Untitled" default. + +1182 +00:47:56,530 --> 00:47:58,960 +I have to make sure that +name doesn't already exist. + +1183 +00:47:58,960 --> 00:48:01,460 +What I'm gonna do here is if it does, + +1184 +00:48:01,460 --> 00:48:04,360 +I'm going to create a unique name. + +1185 +00:48:04,360 --> 00:48:06,400 +So I'm gonna take here, + +1186 +00:48:06,400 --> 00:48:10,360 +let uniqueName equal this name + +1187 +00:48:10,360 --> 00:48:13,430 +that you're asking me to do, unique-ified, + +1188 +00:48:13,430 --> 00:48:15,180 +and I have this nice function that I wrote + +1189 +00:48:15,180 --> 00:48:20,180 +called withRespectTo documentNames.values. + +1190 +00:48:20,620 --> 00:48:23,400 +So this unique-ifies, + +1191 +00:48:23,400 --> 00:48:26,527 +this String with respect +to these other Strings. + +1192 +00:48:26,527 --> 00:48:27,690 +And these other Strings + +1193 +00:48:27,690 --> 00:48:28,970 +are the values of my documentNames. + +1194 +00:48:28,970 --> 00:48:32,620 +In other words, the documentNames +I already know about. + +1195 +00:48:32,620 --> 00:48:35,810 +Let's take a look at this +uniqued withRespectTo real quick. + +1196 +00:48:35,810 --> 00:48:37,660 +It's down here in EmojiArtExtensions. + +1197 +00:48:38,959 --> 00:48:40,550 +It's a real simple little function. + +1198 +00:48:40,550 --> 00:48:42,710 +It just creates a copy of myself, + +1199 +00:48:42,710 --> 00:48:44,000 +this is in String right? + +1200 +00:48:44,000 --> 00:48:49,000 +Copy of myself, and while +I am in this otherStrings, + +1201 +00:48:49,510 --> 00:48:52,010 +I'm going to increment myself. + +1202 +00:48:52,010 --> 00:48:54,220 +Now, what is incrementing myself? + +1203 +00:48:54,220 --> 00:48:56,270 +That's a new thing I added to String, + +1204 +00:48:56,270 --> 00:48:59,760 +where it puts a number +at the end of the String + +1205 +00:48:59,760 --> 00:49:02,000 +and just increments it as necessary + +1206 +00:49:02,000 --> 00:49:04,290 +to finally find a unique number. + +1207 +00:49:04,290 --> 00:49:07,740 +So if my name is "Untitled", + +1208 +00:49:07,740 --> 00:49:10,230 +and there's something else +already called "Untitled", + +1209 +00:49:10,230 --> 00:49:12,487 +I'm gonna eventually become "Untitled1" + +1210 +00:49:12,487 --> 00:49:13,887 +And if my name is "Untitled1", + +1211 +00:49:14,780 --> 00:49:17,270 +and I do incremented, this little code, + +1212 +00:49:17,270 --> 00:49:18,320 +which you can look at later, + +1213 +00:49:18,320 --> 00:49:20,030 +it's kinda fun code actually, + +1214 +00:49:20,030 --> 00:49:23,640 +is gonna go "Untitled2", +"Untitled3", "Untitled4", + +1215 +00:49:23,640 --> 00:49:25,663 +until we find a unique name. + +1216 +00:49:26,544 --> 00:49:29,420 +And so it's just kind of +simple, simple tricky thing. + +1217 +00:49:29,420 --> 00:49:31,087 +But I actually am showing you this, + +1218 +00:49:31,087 --> 00:49:33,860 +and I used this because I want +to show you something else. + +1219 +00:49:33,860 --> 00:49:35,670 +If we go back to our Store, + +1220 +00:49:35,670 --> 00:49:37,070 +this line of code that I wrote + +1221 +00:49:37,070 --> 00:49:39,210 +that did that, didn't actually work. + +1222 +00:49:39,210 --> 00:49:42,480 +It says cannot convert value of type + +1223 +00:49:42,480 --> 00:49:45,740 +Dictionary<EmojiArt, String>.Values + +1224 +00:49:45,740 --> 00:49:47,753 +to expected type, Array of String. + +1225 +00:49:49,340 --> 00:49:51,640 +Yeah, indeed my EmojiArt +extensions over here + +1226 +00:49:51,640 --> 00:49:53,640 +takes an Array of otherStrings, + +1227 +00:49:53,640 --> 00:49:56,760 +which it wants to be unique withRespectTo. + +1228 +00:49:56,760 --> 00:50:01,130 +But back here, this is +not an Array of Strings. + +1229 +00:50:01,130 --> 00:50:03,540 +If you have a Dictionary +like documentNames, + +1230 +00:50:03,540 --> 00:50:05,440 +and you ask for its values, + +1231 +00:50:05,440 --> 00:50:08,710 +you do not get an Array of these things. + +1232 +00:50:08,710 --> 00:50:10,830 +You get a special type that + +1233 +00:50:10,830 --> 00:50:13,780 +is a Collection of these things. + +1234 +00:50:13,780 --> 00:50:16,150 +So we're using functional programming here + +1235 +00:50:16,150 --> 00:50:18,240 +to create, return something that + +1236 +00:50:18,240 --> 00:50:21,090 +it's not an Array, but it is a Collection. + +1237 +00:50:21,090 --> 00:50:23,970 +Now, my unique-ified really +should be just as happy + +1238 +00:50:23,970 --> 00:50:27,440 +to work with a Collection +of Strings, as an Array. + +1239 +00:50:27,440 --> 00:50:30,770 +For example, a Set of +Strings should work here. + +1240 +00:50:30,770 --> 00:50:32,380 +If I want my name unique-ified + +1241 +00:50:32,380 --> 00:50:35,110 +with respect to a Set of other +Strings, that should work. + +1242 +00:50:35,110 --> 00:50:37,400 +And certainly, I'd like to be able to pass + +1243 +00:50:37,400 --> 00:50:42,140 +these values of a Dictionary, +whatever this collection is. + +1244 +00:50:42,140 --> 00:50:44,090 +So how can I make this over here? + +1245 +00:50:44,090 --> 00:50:47,110 +So this doesn't take an +Array of String anymore, + +1246 +00:50:47,110 --> 00:50:49,870 +but it actually takes a Collection, + +1247 +00:50:49,870 --> 00:50:53,093 +and where that Collection +has Strings in it. + +1248 +00:50:53,930 --> 00:50:56,420 +To do this, this is not +object-oriented programming, + +1249 +00:50:56,420 --> 00:50:59,150 +so it's not like a Set, an Array, + +1250 +00:50:59,150 --> 00:51:01,250 +inherit from some class or collection, + +1251 +00:51:01,250 --> 00:51:03,100 +this is functional programming. + +1252 +00:51:03,100 --> 00:51:06,200 +So we're gonna do this way +we always do these things, + +1253 +00:51:06,200 --> 00:51:09,020 +with a don't care and constraining. + +1254 +00:51:09,020 --> 00:51:11,540 +So this is constrains and gains. + +1255 +00:51:11,540 --> 00:51:12,373 +So how are we gonna do this? + +1256 +00:51:12,373 --> 00:51:14,480 +I'm gonna create a don't care here, + +1257 +00:51:14,480 --> 00:51:16,960 +which I'm gonna call StringCollection. + +1258 +00:51:16,960 --> 00:51:19,260 +So I'm gonna unique-ify with respect + +1259 +00:51:19,260 --> 00:51:21,340 +to some StringCollection. + +1260 +00:51:21,340 --> 00:51:24,080 +Now, I'm not totally don't care on this. + +1261 +00:51:24,080 --> 00:51:25,943 +It has to be a Collection, + +1262 +00:51:25,943 --> 00:51:28,280 +because I wanna do contains on it, + +1263 +00:51:28,280 --> 00:51:30,410 +and it also has to have Strings in it, + +1264 +00:51:30,410 --> 00:51:33,820 +because I'm trying to unique-ify +withRespectTo Strings. + +1265 +00:51:33,820 --> 00:51:36,920 +So how do a don't care, with +just a function like this? + +1266 +00:51:36,920 --> 00:51:40,080 +This is not don't care on +String or something else, + +1267 +00:51:40,080 --> 00:51:42,760 +it's just this one little +function on its own, + +1268 +00:51:42,760 --> 00:51:45,090 +wants to have a don't care. + +1269 +00:51:45,090 --> 00:51:47,387 +It does that with <StringCollection>. + +1270 +00:51:49,330 --> 00:51:51,770 +It's very similar to doing it on a type, + +1271 +00:51:51,770 --> 00:51:54,870 +a struct, or whatever, +just do it right here. + +1272 +00:51:54,870 --> 00:51:57,010 +And I can also do the where. + +1273 +00:51:57,010 --> 00:52:01,740 +So I'm gonna do over here, +where this StringCollection + +1274 +00:52:01,740 --> 00:52:04,650 +is a Collection, gotta be a Collection, + +1275 +00:52:04,650 --> 00:52:08,730 +and also, where the StringCollection's + +1276 +00:52:08,730 --> 00:52:11,690 +Element equals String. + +1277 +00:52:11,690 --> 00:52:16,230 +So this.Element is a +don't care in Collection. + +1278 +00:52:16,230 --> 00:52:18,960 +Remember that, a protocol like Collection, + +1279 +00:52:18,960 --> 00:52:22,060 +it can have a don't care associated types. + +1280 +00:52:22,060 --> 00:52:24,660 +And so, it has one, it's just the element, + +1281 +00:52:24,660 --> 00:52:26,380 +and Array has the same one, + +1282 +00:52:26,380 --> 00:52:29,680 +and a Set has this one +because they're getting it + +1283 +00:52:29,680 --> 00:52:31,530 +from Collection 'cause they implement + +1284 +00:52:31,530 --> 00:52:33,300 +the Collection protocol. + +1285 +00:52:33,300 --> 00:52:36,050 +So I'm just constraining +this to make this work. + +1286 +00:52:36,050 --> 00:52:37,170 +Look, this is how it works. + +1287 +00:52:37,170 --> 00:52:39,840 +Because contains is in Collection, + +1288 +00:52:39,840 --> 00:52:43,010 +and of course, we can do things to it here + +1289 +00:52:43,010 --> 00:52:45,060 +that are String-oriented +because I'm making sure + +1290 +00:52:45,060 --> 00:52:46,920 +this is a Collection of Strings. + +1291 +00:52:46,920 --> 00:52:48,610 +And not only that, but back here, + +1292 +00:52:48,610 --> 00:52:51,510 +when I recompile, this is gonna work. + +1293 +00:52:51,510 --> 00:52:52,730 +This is no longer complaining + +1294 +00:52:52,730 --> 00:52:55,210 +because this is a Collection of Strings + +1295 +00:52:55,210 --> 00:52:56,870 +because this is a Dictionary + +1296 +00:52:56,870 --> 00:52:58,703 +that has Strings as its values. + +1297 +00:53:00,220 --> 00:53:02,250 +Yeah, I just wanted to +take a little detour + +1298 +00:53:02,250 --> 00:53:04,040 +from what we were doing to just throw + +1299 +00:53:04,040 --> 00:53:06,443 +another functional +programming thing at you. + +1300 +00:53:07,690 --> 00:53:10,040 +All right, so we have a unique name here, + +1301 +00:53:10,040 --> 00:53:12,430 +so we can add our document +with this uniqueName. + +1302 +00:53:12,430 --> 00:53:13,300 +So let's do that. + +1303 +00:53:13,300 --> 00:53:15,610 +I'm gonna create a document here + +1304 +00:53:15,610 --> 00:53:19,073 +as a little local var. + +1305 +00:53:20,010 --> 00:53:21,720 +And then, I'm going to say, + +1306 +00:53:21,720 --> 00:53:23,183 +if I can let the URL, + +1307 +00:53:24,130 --> 00:53:26,710 +this is gonna be the URL for this document + +1308 +00:53:26,710 --> 00:53:28,980 +that I'm gonna add, I'm +gonna add a new document, + +1309 +00:53:28,980 --> 00:53:31,210 +so I'm gonna create a +URL for that document. + +1310 +00:53:31,210 --> 00:53:35,500 +It's my directory that my store is in, + +1311 +00:53:35,500 --> 00:53:39,433 +appendingPathComponent, +which is that uniqueName. + +1312 +00:53:40,580 --> 00:53:43,340 +So this is the URL that I would want + +1313 +00:53:43,340 --> 00:53:46,080 +to create this new EmojiArtDocument is. + +1314 +00:53:46,080 --> 00:53:48,810 +Now, I'm doing if let +because maybe my directory + +1315 +00:53:48,810 --> 00:53:51,240 +is nil because someone did init named + +1316 +00:53:51,240 --> 00:53:53,230 +instead of doing init directory. + +1317 +00:53:53,230 --> 00:53:55,990 +In this case, my store isn't +based in the file system, + +1318 +00:53:55,990 --> 00:54:00,980 +so my URL is nil, so I can't +get a URL for this document. + +1319 +00:54:00,980 --> 00:54:03,330 +But if I can get a URL for this document, + +1320 +00:54:03,330 --> 00:54:08,170 +then, the document is just +gonna be an EmojiArtDocument + +1321 +00:54:08,170 --> 00:54:11,290 +with that URL, let's create +a new EmojiArtDocument. + +1322 +00:54:11,290 --> 00:54:13,740 +If not, if we're just doing +the UserDefaults thing, + +1323 +00:54:13,740 --> 00:54:16,763 +then, the document is just +a blank EmojiArtDocument. + +1324 +00:54:18,610 --> 00:54:20,400 +Brand new and 'cause we're in addDocument, + +1325 +00:54:20,400 --> 00:54:22,650 +we're adding new documents. + +1326 +00:54:22,650 --> 00:54:24,870 +Let's pay attention to our +error here first though. + +1327 +00:54:24,870 --> 00:54:27,140 +Oh, yes indeed, we don't wanna be adding + +1328 +00:54:27,140 --> 00:54:29,180 +blank document here, we're going to add + +1329 +00:54:29,180 --> 00:54:31,650 +this document that we just created. + +1330 +00:54:31,650 --> 00:54:32,483 +That's why your warnings, + +1331 +00:54:32,483 --> 00:54:34,640 +you gotta always pay +attention to those warnings. + +1332 +00:54:34,640 --> 00:54:36,860 +And also, let's make +sure that we are using + +1333 +00:54:36,860 --> 00:54:39,230 +the uniqueName that we just created + +1334 +00:54:39,230 --> 00:54:41,093 +as the name of the document there. + +1335 +00:54:43,260 --> 00:54:44,730 +All right, so we have no documents here. + +1336 +00:54:44,730 --> 00:54:48,150 +Let's see, Plus, hopefully +that created a file + +1337 +00:54:48,150 --> 00:54:50,790 +in our file system for that. + +1338 +00:54:50,790 --> 00:54:52,784 +And how about another one? + +1339 +00:54:52,784 --> 00:54:54,640 +Whoa, we got the unique, another? + +1340 +00:54:54,640 --> 00:54:56,570 +Whoa, it incremented, okay, so our little + +1341 +00:54:56,570 --> 00:54:58,200 +increment code worked as well. + +1342 +00:54:58,200 --> 00:55:00,270 +Now, hopefully when we +quit and come back here, + +1343 +00:55:00,270 --> 00:55:03,780 +those three files are gonna +be in the file system. + +1344 +00:55:03,780 --> 00:55:06,580 +And they are excellent. + +1345 +00:55:06,580 --> 00:55:08,440 +Okay, next step, deleting. + +1346 +00:55:08,440 --> 00:55:12,040 +So we go over here and say +let's get rid of "Untitled1". + +1347 +00:55:12,040 --> 00:55:13,710 +Oh, the bugger worked, nice. + +1348 +00:55:13,710 --> 00:55:14,823 +Now, let's rerun. + +1349 +00:55:16,290 --> 00:55:17,533 +Oh, "Untitled1" is back. + +1350 +00:55:17,533 --> 00:55:20,220 +That makes sense, right, +because we didn't, + +1351 +00:55:20,220 --> 00:55:22,110 +when we hit "Done" here and said "Delete", + +1352 +00:55:22,110 --> 00:55:24,280 +we didn't actually delete +it in the file system, + +1353 +00:55:24,280 --> 00:55:27,013 +we deleted it in our +document names, that's it. + +1354 +00:55:28,076 --> 00:55:31,770 +All right, so we gotta go +fix removeDocument here + +1355 +00:55:31,770 --> 00:55:34,770 +to delete the thing from the file system. + +1356 +00:55:34,770 --> 00:55:35,840 +That's probably the easiest + +1357 +00:55:35,840 --> 00:55:37,720 +of all the things we need to do. + +1358 +00:55:37,720 --> 00:55:38,640 +We're just gonna see if we can + +1359 +00:55:38,640 --> 00:55:41,460 +get the URL for that thing, + +1360 +00:55:41,460 --> 00:55:44,000 +which we have to get from its name, + +1361 +00:55:44,000 --> 00:55:47,193 +that's our documentNames +for that Document. + +1362 +00:55:48,140 --> 00:55:51,740 +And then, letting the +URL equal our directory, + +1363 +00:55:51,740 --> 00:55:56,740 +and appending the +PathComponent of that name. + +1364 +00:55:58,100 --> 00:56:00,660 +So, if this Document that +we're trying to remove, + +1365 +00:56:00,660 --> 00:56:02,780 +it's already, we've got a name for it, + +1366 +00:56:02,780 --> 00:56:04,360 +and we can make a URL out of it, + +1367 +00:56:04,360 --> 00:56:07,410 +meaning that we're a Store +that's in a directory. + +1368 +00:56:07,410 --> 00:56:08,500 +We're just gonna remove it. + +1369 +00:56:08,500 --> 00:56:09,570 +And that's another thing that + +1370 +00:56:09,570 --> 00:56:11,530 +our FileManager can do for us. + +1371 +00:56:11,530 --> 00:56:14,324 +FileManager.default shared one, + +1372 +00:56:14,324 --> 00:56:17,713 +removeItem at URL, kaboom. + +1373 +00:56:18,780 --> 00:56:19,997 +Now again, like most of these + +1374 +00:56:19,997 --> 00:56:23,360 +FileManagers things, this can throw. + +1375 +00:56:23,360 --> 00:56:25,200 +This one, in this case, I'm just going + +1376 +00:56:25,200 --> 00:56:26,840 +to do the try? + +1377 +00:56:26,840 --> 00:56:29,050 +because we're trying to +remove this document, + +1378 +00:56:29,050 --> 00:56:29,990 +and I can't remove it. + +1379 +00:56:29,990 --> 00:56:31,840 +I'm not sure what I'm gonna do about it. + +1380 +00:56:31,840 --> 00:56:33,470 +I supposed I could look at these errors, + +1381 +00:56:33,470 --> 00:56:37,170 +and see if there's one that's +recoverable in some way + +1382 +00:56:37,170 --> 00:56:39,830 +but probably unlikely. + +1383 +00:56:39,830 --> 00:56:42,313 +That did it, removeDocument done. + +1384 +00:56:44,573 --> 00:56:47,840 +Now, let's try and remove "Untitled1". + +1385 +00:56:47,840 --> 00:56:50,183 +All right, done, and rerun. + +1386 +00:56:51,800 --> 00:56:56,800 +Gone, nice, add this +back, add another one. + +1387 +00:56:56,850 --> 00:56:59,640 +Let's go here, delete "Untitled3", + +1388 +00:56:59,640 --> 00:57:03,813 +let's delete "Untitled", done, rerun. + +1389 +00:57:05,270 --> 00:57:09,840 +Whoa, okay, so the last one I +think we have here is rename. + +1390 +00:57:09,840 --> 00:57:11,547 +So if I go edit here and I say, + +1391 +00:57:11,547 --> 00:57:14,427 +"I wanna change this +back to being "Untitled", + +1392 +00:57:14,427 --> 00:57:17,080 +"and I hit Done," looks like it works. + +1393 +00:57:17,080 --> 00:57:22,080 +Three run, oh no, "Untitled1" is back. + +1394 +00:57:22,460 --> 00:57:25,030 +So again, I'm renaming. + +1395 +00:57:25,030 --> 00:57:26,740 +It's having no effect on the file system, + +1396 +00:57:26,740 --> 00:57:28,760 +so it just comes back and shows you + +1397 +00:57:28,760 --> 00:57:31,023 +what was in the file system when we rerun. + +1398 +00:57:31,880 --> 00:57:33,980 +Let's change setName. + +1399 +00:57:33,980 --> 00:57:36,930 +This one's just a matter +of changing the URL + +1400 +00:57:36,930 --> 00:57:39,370 +for this document right here to be a URL + +1401 +00:57:39,370 --> 00:57:40,830 +that works for this name. + +1402 +00:57:40,830 --> 00:57:44,630 +So if I can let url equal our directory + +1403 +00:57:44,630 --> 00:57:49,630 +by appending the +PathComponent of this name + +1404 +00:57:49,650 --> 00:57:51,780 +that you wanna set as the new thing, + +1405 +00:57:51,780 --> 00:57:56,420 +then, the document.url = url. + +1406 +00:57:56,420 --> 00:57:59,130 +I've just changed the place, +where this is happening. + +1407 +00:57:59,130 --> 00:58:02,040 +Now, I know, one other thing though, + +1408 +00:58:02,040 --> 00:58:04,550 +what if this is a rename? + +1409 +00:58:04,550 --> 00:58:06,890 +Okay, someone said the name of a document, + +1410 +00:58:06,890 --> 00:58:09,550 +and it had, was already around somewhere + +1411 +00:58:09,550 --> 00:58:12,170 +in our document name +with a different name. + +1412 +00:58:12,170 --> 00:58:14,050 +So good to be careful of that. + +1413 +00:58:14,050 --> 00:58:17,633 +How about if we remove the old document? + +1414 +00:58:18,784 --> 00:58:21,400 +If we remove this old document +before we change its URL, + +1415 +00:58:21,400 --> 00:58:23,790 +it'll remove it from its old URL, + +1416 +00:58:23,790 --> 00:58:26,800 +and now, we put it in its new URL. + +1417 +00:58:26,800 --> 00:58:29,540 +But there's one other thing with naming, + +1418 +00:58:29,540 --> 00:58:32,810 +it's a little tricky, +similar to addDocument, + +1419 +00:58:32,810 --> 00:58:35,340 +which is what if you try to set the name + +1420 +00:58:35,340 --> 00:58:37,650 +of a Document to the same name + +1421 +00:58:37,650 --> 00:58:40,712 +as some other Document already has. + +1422 +00:58:40,712 --> 00:58:45,360 +Oh yeah, well, we could +try some unique vocation + +1423 +00:58:45,360 --> 00:58:47,010 +or something like that. + +1424 +00:58:47,010 --> 00:58:48,290 +But I actually think the strategy + +1425 +00:58:48,290 --> 00:58:51,420 +I'm gonna use is I'm just +gonna reject that request. + +1426 +00:58:51,420 --> 00:58:54,010 +I'm simply just going to ignore it. + +1427 +00:58:54,010 --> 00:58:56,590 +Again, maybe I wanna enhance this func + +1428 +00:58:56,590 --> 00:58:59,080 +to return a Bool, whether I was able + +1429 +00:58:59,080 --> 00:59:00,500 +to actually do this rename, + +1430 +00:59:00,500 --> 00:59:03,600 +and then, the UI could +put up an Alert, whatever. + +1431 +00:59:03,600 --> 00:59:05,920 +We're doing a demo, so I'm +not gonna do any of that. + +1432 +00:59:05,920 --> 00:59:10,060 +I'm just not going to allow +a rename to happen here, + +1433 +00:59:10,060 --> 00:59:12,950 +if you're trying to do +one in the file system, + +1434 +00:59:12,950 --> 00:59:14,800 +and that name exists. + +1435 +00:59:14,800 --> 00:59:15,770 +So the way I'm gonna do that + +1436 +00:59:15,770 --> 00:59:19,920 +is I'm gonna say, if the, I'll do this + +1437 +00:59:19,920 --> 00:59:24,880 +if the documentNames.values +does not contain this name, + +1438 +00:59:24,880 --> 00:59:28,120 +then, I'm happy to rename this for you. + +1439 +00:59:28,120 --> 00:59:29,640 +Otherwise, I'm not gonna do it. + +1440 +00:59:29,640 --> 00:59:31,390 +And in fact, otherwise, +I'm not gonna do anything. + +1441 +00:59:31,390 --> 00:59:36,267 +So let's put this one down +here in an else like that. + +1442 +00:59:36,267 --> 00:59:38,230 +And then, do this up here + +1443 +00:59:38,230 --> 00:59:42,573 +only if this don't have +this name conflict. + +1444 +00:59:43,590 --> 00:59:44,990 +Well, let's see what happens in the UI + +1445 +00:59:44,990 --> 00:59:46,240 +if I just take this strategy, + +1446 +00:59:46,240 --> 00:59:51,090 +just not allowing renames, +that to another name. + +1447 +00:59:51,090 --> 00:59:52,040 +So here we go, let's try. + +1448 +00:59:52,040 --> 00:59:53,600 +Well, first of all, let's +see if rename is working. + +1449 +00:59:53,600 --> 00:59:55,160 +So here I'm gonna do "Untitled1", + +1450 +00:59:55,160 --> 00:59:58,040 +I'm gonna rename it to be "Untitled". + +1451 +00:59:58,040 --> 00:59:59,350 +That's not the name of something else, + +1452 +00:59:59,350 --> 01:00:00,873 +that's good, let's rerun. + +1453 +01:00:02,644 --> 01:00:04,520 +Oh, it renamed it in the file system. + +1454 +01:00:04,520 --> 01:00:08,200 +Okay now, let's try, and +take this "Untitled2", + +1455 +01:00:08,200 --> 01:00:11,387 +and call it "Untitled", done. + +1456 +01:00:11,387 --> 01:00:14,450 +Oh, look, it didn't allow me to do that. + +1457 +01:00:14,450 --> 01:00:16,050 +But when I went back, it was here. + +1458 +01:00:16,050 --> 01:00:19,697 +That's interesting, so +let's try "Untitled1". + +1459 +01:00:19,697 --> 01:00:22,500 +Yeah, that works, okay, +let's add a few more. + +1460 +01:00:22,500 --> 01:00:26,587 +Let's try and rename +"Untitled4" to be "Untitled2". + +1461 +01:00:28,100 --> 01:00:30,920 +Done, oh, wouldn't allow +it, just went back. + +1462 +01:00:30,920 --> 01:00:32,610 +But when I go back to Edit, + +1463 +01:00:32,610 --> 01:00:34,640 +it's still holding onto that "2" for me. + +1464 +01:00:34,640 --> 01:00:38,713 +So maybe I really want +"21" or maybe I want "2a", + +1465 +01:00:40,403 --> 01:00:41,837 +something like that. + +1466 +01:00:41,837 --> 01:00:44,160 +And that, it allows. + +1467 +01:00:44,160 --> 01:00:46,673 +So it's not too bad that we just rejected. + +1468 +01:00:47,960 --> 01:00:50,360 +I probably would prefer +a little Alert there, + +1469 +01:00:50,360 --> 01:00:54,530 +maybe just because the user +might be a little confused. + +1470 +01:00:54,530 --> 01:00:55,910 +They're here, and they said this, + +1471 +01:00:55,910 --> 01:00:57,757 +and they hit "Done", and +they think, "Oh, they did it, + +1472 +01:00:57,757 --> 01:00:59,857 +"but oh, there's that "2a", it's back. + +1473 +01:00:59,857 --> 01:01:00,690 +"What's going on? + +1474 +01:01:00,690 --> 01:01:01,717 +"I tried to rename that." + +1475 +01:01:02,640 --> 01:01:04,650 +Yeah, they may or may not notice it + +1476 +01:01:04,650 --> 01:01:05,890 +there's another one with that name. + +1477 +01:01:05,890 --> 01:01:08,090 +So maybe an Alert that name is already + +1478 +01:01:08,090 --> 01:01:09,533 +in use would be good here. + +1479 +01:01:11,530 --> 01:01:12,827 +But we're here to learn about file system, + +1480 +01:01:12,827 --> 01:01:14,960 +and I think we did that. + +1481 +01:01:14,960 --> 01:01:18,150 +We showed a lot of different +parts of file system here. + +1482 +01:01:18,150 --> 01:01:20,040 +We started out over in our document, + +1483 +01:01:20,040 --> 01:01:22,780 +just learning how we can use Data, + +1484 +01:01:22,780 --> 01:01:25,540 +and URL to change our reading, + +1485 +01:01:25,540 --> 01:01:28,355 +and writing to be going +out to the file system, + +1486 +01:01:28,355 --> 01:01:29,490 +instead of UserDefaults. + +1487 +01:01:29,490 --> 01:01:32,750 +That was super easy over here. + +1488 +01:01:32,750 --> 01:01:34,550 +And then, when we went to the store, + +1489 +01:01:34,550 --> 01:01:36,620 +we learned a lot of +things about FileManager, + +1490 +01:01:36,620 --> 01:01:39,120 +the shared FileManager like how to get + +1491 +01:01:39,120 --> 01:01:41,110 +all the contents of a directory, + +1492 +01:01:41,110 --> 01:01:43,210 +and then, how to do things +with the FileManager + +1493 +01:01:43,210 --> 01:01:44,813 +like remove files. + +1494 +01:01:46,100 --> 01:01:48,320 +So that is it for this demo, + +1495 +01:01:48,320 --> 01:01:50,810 +and hopefully, you'll have a chance + +1496 +01:01:50,810 --> 01:01:54,140 +to integrate this into your final project. + +1497 +01:01:54,140 --> 01:01:55,310 +It's pretty straightforward to do, + +1498 +01:01:55,310 --> 01:01:57,700 +and usually you do have +storage requirements, + +1499 +01:01:57,700 --> 01:02:00,200 +and I'd rather not see +all of your final projects + +1500 +01:02:00,200 --> 01:02:02,314 +storing everything in UserDefaults. + +1501 +01:02:02,314 --> 01:02:03,490 +I definitely would like to see + +1502 +01:02:03,490 --> 01:02:07,560 +some Core Data, and or file system, + +1503 +01:02:07,560 --> 01:02:10,323 +and maybe even CloudKit, +that would be great. + +1504 +01:02:11,480 --> 01:02:14,733 +- [Announcer] For more, please +visit us at stanford.edu. diff --git a/subtitles/en/Lecture 14. UIKit Integration b/subtitles/en/Lecture 14. UIKit Integration new file mode 100644 index 0000000..48f2b37 --- /dev/null +++ b/subtitles/en/Lecture 14. UIKit Integration @@ -0,0 +1,6024 @@ +1 +00:00:00,000 --> 00:00:02,417 +(soft music) + +2 +00:00:04,477 --> 00:00:06,323 +- [Woman] Stanford University. + +3 +00:00:07,710 --> 00:00:10,909 +- [Instructor] Welcome everyone +to the very last lecture, + +4 +00:00:10,909 --> 00:00:14,797 +lecture number 14 of Stanford CS193p + +5 +00:00:14,797 --> 00:00:18,053 +during Spring quarter of 2020. + +6 +00:00:18,939 --> 00:00:21,054 +For all of you it's all final project + +7 +00:00:21,054 --> 00:00:22,471 +all the rest of the way. + +8 +00:00:22,471 --> 00:00:27,085 +However, I do want to talk about +one last feature in SwiftUI + +9 +00:00:27,085 --> 00:00:29,786 +which is the integration with UIKit. + +10 +00:00:29,786 --> 00:00:32,390 +Remember that UIKit is the old way + +11 +00:00:32,390 --> 00:00:35,234 +of developing applications for iOS. + +12 +00:00:35,234 --> 00:00:38,610 +And when SwiftUI came +out a few months ago, + +13 +00:00:38,610 --> 00:00:41,450 +it does pretty much +everything that UIKit does + +14 +00:00:41,450 --> 00:00:43,860 +but there's a few UIKit features in there + +15 +00:00:43,860 --> 00:00:44,960 +that aren't in SwiftUI, + +16 +00:00:44,960 --> 00:00:47,161 +and you'd like to be able to use them, + +17 +00:00:47,161 --> 00:00:49,976 +and so this API makes it +really easy to do that. + +18 +00:00:49,976 --> 00:00:53,656 +Also you might be an existing +developer of an iOS app + +19 +00:00:53,656 --> 00:00:55,755 +and you've got a bunch of UIKit code, + +20 +00:00:55,755 --> 00:00:56,960 +of course you wanna use that + +21 +00:00:56,960 --> 00:00:59,200 +as you transition over to SwiftUI, + +22 +00:00:59,200 --> 00:01:02,712 +and this lets you do that as well. + +23 +00:01:02,712 --> 00:01:04,853 +Now for me to talk about this feature, + +24 +00:01:04,853 --> 00:01:07,757 +I have to explain a little +bit about how UIKit works. + +25 +00:01:07,757 --> 00:01:10,539 +I'm not gonna teach you any UIKit itself, + +26 +00:01:10,539 --> 00:01:12,584 +but conceptually it's important + +27 +00:01:12,584 --> 00:01:15,230 +to understand some basics about it. + +28 +00:01:15,230 --> 00:01:18,663 +One thing is there's no MVVM in UIKit, + +29 +00:01:18,663 --> 00:01:22,880 +instead it's something called +MVC, Model-View-Controller. + +30 +00:01:22,880 --> 00:01:25,233 +And in the Model-View-Controller +architecture, + +31 +00:01:25,233 --> 00:01:27,446 +Views are kind of grouped together + +32 +00:01:27,446 --> 00:01:31,166 +and controlled by something +called a Controller. + +33 +00:01:31,166 --> 00:01:34,784 +This Controller is sort of the granularity + +34 +00:01:34,784 --> 00:01:37,171 +at which you present Views on screen. + +35 +00:01:37,171 --> 00:01:40,739 +And by presenting I +mean like SwiftUI sheet + +36 +00:01:40,739 --> 00:01:43,864 +or popover or the destination +of a NavigationLink. + +37 +00:01:43,864 --> 00:01:46,166 +Those are presenting Views on screen. + +38 +00:01:46,166 --> 00:01:48,521 +Well, in SwiftUI there's no difference. + +39 +00:01:48,521 --> 00:01:51,820 +We don't have any Controllers, +so Views are just Views, + +40 +00:01:51,820 --> 00:01:53,610 +and we present them whenever we want. + +41 +00:01:53,610 --> 00:01:54,951 +It's quite nice. + +42 +00:01:54,951 --> 00:01:57,357 +But in UIKit, it's different + +43 +00:01:57,357 --> 00:01:59,268 +when you're putting Views on screen. + +44 +00:01:59,268 --> 00:02:01,917 +You have to essentially +present a Controller, + +45 +00:02:01,917 --> 00:02:05,114 +and the Controller controls Views. + +46 +00:02:05,114 --> 00:02:06,498 +Now because of this, + +47 +00:02:06,498 --> 00:02:08,343 +because you've got this Controller thing, + +48 +00:02:08,343 --> 00:02:11,895 +the integration between SwiftUI and UIKit + +49 +00:02:11,895 --> 00:02:14,285 +really needs two integration points. + +50 +00:02:14,285 --> 00:02:16,534 +Now these two integration +points are very similar, + +51 +00:02:16,534 --> 00:02:19,296 +but one is a UIViewRepresentable, + +52 +00:02:19,296 --> 00:02:23,419 +that's a SwiftUI View that +represents a UIKit View, + +53 +00:02:23,419 --> 00:02:27,752 +and then there's also +UIViewControllerRepresentable, + +54 +00:02:27,752 --> 00:02:31,046 +a SwiftUI View that represents +one of these Controllers + +55 +00:02:31,046 --> 00:02:34,835 +and all the Views that +that Controller controls. + +56 +00:02:34,835 --> 00:02:36,677 +We can see these things look the same + +57 +00:02:36,677 --> 00:02:38,880 +but it's just necessary to have both + +58 +00:02:38,880 --> 00:02:42,600 +because of UIKit's underlying +dichotomy between their Views + +59 +00:02:42,600 --> 00:02:44,731 +like Buttons and +TextFields, those are Views, + +60 +00:02:44,731 --> 00:02:46,277 +and their ViewControllers + +61 +00:02:46,277 --> 00:02:49,074 +which are these groupings of Views. + +62 +00:02:49,074 --> 00:02:50,538 +And the main work that's involved + +63 +00:02:50,538 --> 00:02:53,576 +in implementing either of +these two Representables + +64 +00:02:53,576 --> 00:02:56,400 +is dealing with setting of the vars + +65 +00:02:56,400 --> 00:02:58,973 +to configure the View +or the ViewController. + +66 +00:02:58,973 --> 00:03:01,070 +And especially with the ViewControllers, + +67 +00:03:01,070 --> 00:03:03,431 +they often want to call you back + +68 +00:03:03,431 --> 00:03:05,906 +and say this happened in my ViewController + +69 +00:03:05,906 --> 00:03:08,936 +and what should I do about +it and things like that. + +70 +00:03:08,936 --> 00:03:12,398 +I say here, quote, "callback +functions" on the slide, + +71 +00:03:12,398 --> 00:03:15,559 +but it's not really +callback functions per se. + +72 +00:03:15,559 --> 00:03:17,823 +And I'm gonna dive into +that a little bit more now + +73 +00:03:17,823 --> 00:03:18,994 +so you can understand + +74 +00:03:18,994 --> 00:03:23,056 +how this mechanism of a View is on screen + +75 +00:03:23,056 --> 00:03:25,233 +or a ViewController is one +thing and things are happening, + +76 +00:03:25,233 --> 00:03:29,133 +how do we interact with +it, works in UIKit. + +77 +00:03:29,986 --> 00:03:33,147 +The main concept there +that you need to understand + +78 +00:03:33,147 --> 00:03:35,451 +is something called delegation. + +79 +00:03:35,451 --> 00:03:37,919 +Remember UIKit is object-oriented? + +80 +00:03:37,919 --> 00:03:40,600 +Not functional programming, +it's object-oriented. + +81 +00:03:40,600 --> 00:03:41,433 +So it's very different. + +82 +00:03:41,433 --> 00:03:43,486 +It's not declarative, it's not reactive, + +83 +00:03:43,486 --> 00:03:44,845 +none of those things. + +84 +00:03:44,845 --> 00:03:49,264 +And it uses heavily a +concept called delegation. + +85 +00:03:49,264 --> 00:03:52,214 +We briefly mentioned this when +we talked about FileManager. + +86 +00:03:52,214 --> 00:03:53,926 +FileManager has a delegate. + +87 +00:03:53,926 --> 00:03:56,981 +But these objects, these +Controllers and their Views, + +88 +00:03:56,981 --> 00:04:00,945 +have a delegate that +they literally delegate + +89 +00:04:00,945 --> 00:04:02,549 +functionality to. + +90 +00:04:02,549 --> 00:04:05,042 +Some of the functionalities +of Views and ViewController, + +91 +00:04:05,042 --> 00:04:08,871 +they offer to allow some +other object to control that. + +92 +00:04:08,871 --> 00:04:11,634 +Now they do this by having +a var in themselves. + +93 +00:04:11,634 --> 00:04:13,150 +The Views or ViewControllers + +94 +00:04:13,150 --> 00:04:15,321 +have a var in themselves +called a delegate. + +95 +00:04:15,321 --> 00:04:19,780 +And this delegate var its +type is some protocol. + +96 +00:04:19,780 --> 00:04:22,270 +Now we know protocols well of course + +97 +00:04:22,270 --> 00:04:24,020 +as functional programmers. + +98 +00:04:24,020 --> 00:04:24,913 +In object-oriented programming, + +99 +00:04:24,913 --> 00:04:26,910 +protocols are used not as much, + +100 +00:04:26,910 --> 00:04:28,680 +and the protocols are slightly different + +101 +00:04:28,680 --> 00:04:31,522 +in that the methods and +vars in the protocol, + +102 +00:04:31,522 --> 00:04:33,717 +some of them can be optional. + +103 +00:04:33,717 --> 00:04:35,786 +Not optional like the enum Optional, + +104 +00:04:35,786 --> 00:04:39,100 +but optional like you don't +have to implement them. + +105 +00:04:39,100 --> 00:04:40,838 +You're gonna see when +we do our demos today, + +106 +00:04:40,838 --> 00:04:44,286 +we're going to do a couple of +different delegate protocols + +107 +00:04:44,286 --> 00:04:45,560 +and we're only gonna implement + +108 +00:04:45,560 --> 00:04:47,584 +one or two methods in each one + +109 +00:04:47,584 --> 00:04:51,526 +even though there might be +10 or 15 methods available. + +110 +00:04:51,526 --> 00:04:53,864 +You might not need to use all of them. + +111 +00:04:53,864 --> 00:04:56,356 +This delegate var has this object + +112 +00:04:56,356 --> 00:04:58,233 +which can be pretty much anything + +113 +00:04:58,233 --> 00:05:00,750 +as long as it implements this protocol. + +114 +00:05:00,750 --> 00:05:02,700 +And this protocol has a +lot of things in there + +115 +00:05:02,700 --> 00:05:06,071 +like I will do this and should I do this + +116 +00:05:06,071 --> 00:05:07,546 +and I just did do this. + +117 +00:05:07,546 --> 00:05:09,871 +Those kinds of notifications are happening + +118 +00:05:09,871 --> 00:05:12,809 +between the View or +ViewController and this delegate. + +119 +00:05:12,809 --> 00:05:16,478 +So when we do our integration +between SwiftUI and UIKit, + +120 +00:05:16,478 --> 00:05:19,721 +we have to somehow provide this delegate + +121 +00:05:19,721 --> 00:05:22,434 +so that this View or +ViewController can function + +122 +00:05:22,434 --> 00:05:24,312 +'cause a lot of times +they need that delegate + +123 +00:05:24,312 --> 00:05:27,930 +to do anything of any substance. + +124 +00:05:27,930 --> 00:05:30,251 +So I decided in the two +demos that I'm doing today, + +125 +00:05:30,251 --> 00:05:32,521 +I'm gonna do one ViewRepresentable demo + +126 +00:05:32,521 --> 00:05:34,552 +and one ViewControllerRepresentable. + +127 +00:05:34,552 --> 00:05:36,720 +Both of them are gonna have a delegate + +128 +00:05:36,720 --> 00:05:39,163 +so you can see how that integrates. + +129 +00:05:40,672 --> 00:05:45,058 +So let's talk about these +Representables, these two + +130 +00:05:45,058 --> 00:05:48,525 +SwiftUI Views, UIViewRepresentable and + +131 +00:05:48,525 --> 00:05:49,685 +UIViewControllerRepresentable, +they're super similar + +132 +00:05:49,685 --> 00:05:53,013 +and they both have these +five main components. + +133 +00:05:53,013 --> 00:05:56,260 +The first one is just +a function that makes, + +134 +00:05:56,260 --> 00:05:59,727 +creates the underlying +View or ViewController, + +135 +00:05:59,727 --> 00:06:02,980 +the so-called makeUIView +or makeUIViewController. + +136 +00:06:02,980 --> 00:06:04,303 +And you go pass this context + +137 +00:06:04,303 --> 00:06:05,536 +which I'll talk about in a minute, + +138 +00:06:05,536 --> 00:06:08,346 +and you just return the +View or the ViewController + +139 +00:06:08,346 --> 00:06:13,346 +that is Representable, +is basically representing + +140 +00:06:13,410 --> 00:06:14,243 +with some SwiftUI Views. + +141 +00:06:14,243 --> 00:06:16,169 +So that's obvious we need that. + +142 +00:06:16,169 --> 00:06:21,084 +Another obvious thing we need +is something to get this UIKit + +143 +00:06:21,084 --> 00:06:26,084 +to participate in the reactive +nature of SwiftUI, right? + +144 +00:06:26,595 --> 00:06:30,358 +When a Binding changes or +ObservableObject changes + +145 +00:06:30,358 --> 00:06:32,905 +or some internal state +changes, something like that, + +146 +00:06:32,905 --> 00:06:36,524 +we do some Intent, changes our Model, + +147 +00:06:36,524 --> 00:06:39,918 +it ripples back to us +and we redraw in the UI, + +148 +00:06:39,918 --> 00:06:41,522 +we are redrawing our Views, + +149 +00:06:41,522 --> 00:06:44,861 +updating them all the time in SwiftUI. + +150 +00:06:44,861 --> 00:06:47,096 +This doesn't really exist in UIKit. + +151 +00:06:47,096 --> 00:06:49,475 +So in your Representable +you have to implement + +152 +00:06:49,475 --> 00:06:53,234 +a function called updateUIView +or updateUIViewController, + +153 +00:06:53,234 --> 00:06:54,067 +and it will pass the ViewController + +154 +00:06:55,023 --> 00:06:56,890 +that you created with makeUIView + +155 +00:06:56,890 --> 00:06:59,030 +back to you along again with this context + +156 +00:06:59,030 --> 00:07:00,180 +which I'll talk about in a second, + +157 +00:07:00,180 --> 00:07:03,269 +and you now update that UIView. + +158 +00:07:03,269 --> 00:07:07,506 +So this is getting called +whenever your SwiftUI View + +159 +00:07:07,506 --> 00:07:11,640 +is part of an update pass, +right, it's being updated, + +160 +00:07:11,640 --> 00:07:14,517 +and so you have to able +to update the View. + +161 +00:07:14,517 --> 00:07:15,740 +You might set vars, + +162 +00:07:15,740 --> 00:07:19,281 +you might pass values, whatever, in there, + +163 +00:07:19,281 --> 00:07:20,413 +you can have Binding. + +164 +00:07:20,413 --> 00:07:21,650 +I mean UIViewRepresentable + +165 +00:07:21,650 --> 00:07:23,438 +and UIViewControllerRepresentable, + +166 +00:07:23,438 --> 00:07:24,955 +they are SwiftUI Views, + +167 +00:07:24,955 --> 00:07:26,573 +of course they can have @Bindings + +168 +00:07:26,573 --> 00:07:29,220 +and maybe you're getting some +values out of these things + +169 +00:07:29,220 --> 00:07:31,731 +that are bound back to +your other SwiftUI Views + +170 +00:07:31,731 --> 00:07:34,080 +and you're setting it in your UIKit View. + +171 +00:07:34,080 --> 00:07:36,587 +So that's what's happening here. + +172 +00:07:36,587 --> 00:07:39,830 +Now this third thing is a +function called makeCoordinator + +173 +00:07:39,830 --> 00:07:43,361 +that's gonna return what's +called a Coordinator. + +174 +00:07:43,361 --> 00:07:45,090 +Now that Coordinator is a don't care. + +175 +00:07:45,090 --> 00:07:47,127 +It can be anything you want, right? + +176 +00:07:47,127 --> 00:07:49,337 +It has no requirements on it. + +177 +00:07:49,337 --> 00:07:52,262 +I'm not even sure it has any +constrains and gains on it. + +178 +00:07:52,262 --> 00:07:55,454 +The main thing about this +Coordinator though is + +179 +00:07:55,454 --> 00:07:57,178 +it's something that's gonna be passed + +180 +00:07:57,178 --> 00:08:00,676 +back to you via that context above. + +181 +00:08:00,676 --> 00:08:02,963 +Alright, so this Coordinator is the thing + +182 +00:08:02,963 --> 00:08:05,334 +that's gonna serve as the delegate + +183 +00:08:05,334 --> 00:08:09,139 +of our UIView or +UIViewController if it needs one. + +184 +00:08:09,139 --> 00:08:12,486 +And it's really nothing +more than a collection + +185 +00:08:12,486 --> 00:08:16,013 +of the functionality that +you would need in a delegate + +186 +00:08:16,013 --> 00:08:20,060 +to make your View or ViewController work. + +187 +00:08:20,060 --> 00:08:21,850 +Really the whole UIView + +188 +00:08:21,850 --> 00:08:23,693 +and UIViewControllerRepresentable system + +189 +00:08:23,693 --> 00:08:25,468 +doesn't even care what this thing is. + +190 +00:08:25,468 --> 00:08:27,620 +It just wants to give you an opportunity + +191 +00:08:27,620 --> 00:08:31,123 +to have some object that +is being the delegate. + +192 +00:08:32,004 --> 00:08:34,854 +Now this context I keep +talking about up here, + +193 +00:08:34,854 --> 00:08:37,243 +this pass to the makeUIView +and updateUIView, + +194 +00:08:38,609 --> 00:08:40,196 +it has three things in it. + +195 +00:08:40,196 --> 00:08:42,430 +One is the Coordinator you created, + +196 +00:08:42,430 --> 00:08:43,977 +the thing that's gonna be the delegate + +197 +00:08:43,977 --> 00:08:45,360 +for your View or ViewController. + +198 +00:08:45,360 --> 00:08:48,345 +It also includes your +SwiftUI's environment + +199 +00:08:48,345 --> 00:08:51,177 +like are you in dark +mode, all those things. + +200 +00:08:51,177 --> 00:08:53,534 +And it contains a transaction. + +201 +00:08:53,534 --> 00:08:55,104 +So this is an animation transaction. + +202 +00:08:55,104 --> 00:08:56,780 +I told you earlier in the quarter + +203 +00:08:56,780 --> 00:08:59,272 +we're not really gonna +talk about transactions, + +204 +00:08:59,272 --> 00:09:01,115 +but it's essentially encapsulating + +205 +00:09:01,115 --> 00:09:04,751 +what sort of animation +environment is going on + +206 +00:09:04,751 --> 00:09:08,778 +while the makeUIView or +updateUIView is happening. + +207 +00:09:08,778 --> 00:09:10,410 +So what this context is. + +208 +00:09:10,410 --> 00:09:11,524 +Mostly out of the context, + +209 +00:09:11,524 --> 00:09:13,867 +you're gonna be grabbing environment stuff + +210 +00:09:13,867 --> 00:09:15,335 +or you're gonna get your Coordinator + +211 +00:09:15,335 --> 00:09:17,670 +so you can talk to the delegate + +212 +00:09:17,670 --> 00:09:19,977 +basically of your View and ViewController. + +213 +00:09:19,977 --> 00:09:21,200 +I don't wanna make it sound like + +214 +00:09:21,200 --> 00:09:22,473 +your Coordinator can only be the delegate, + +215 +00:09:22,473 --> 00:09:25,740 +but that's the primary, +probably the primary thing + +216 +00:09:25,740 --> 00:09:28,055 +you'll use the Coordinator for. + +217 +00:09:28,055 --> 00:09:30,480 +And then finally there +is a tear down phase + +218 +00:09:30,480 --> 00:09:33,041 +when your SwiftUI View is going away. + +219 +00:09:33,041 --> 00:09:34,503 +Of course you wanna be able to clean up + +220 +00:09:34,503 --> 00:09:37,954 +your ViewController or your +View it just passed back to you + +221 +00:09:37,954 --> 00:09:40,690 +along with your coordinator, +your delegate or whatever + +222 +00:09:40,690 --> 00:09:43,220 +so you could clean that +up as well if you have to. + +223 +00:09:43,220 --> 00:09:45,517 +You can do whatever is necessary there. + +224 +00:09:45,517 --> 00:09:46,592 +That's it. + +225 +00:09:46,592 --> 00:09:48,128 +Pretty much that's how you make it, + +226 +00:09:48,128 --> 00:09:50,859 +you update when the passes happen through, + +227 +00:09:50,859 --> 00:09:52,036 +you've got a little Coordinator, + +228 +00:09:52,036 --> 00:09:53,572 +you can have your delegate, + +229 +00:09:53,572 --> 00:09:56,903 +and then you can dismantle +it when things are all done. + +230 +00:09:58,539 --> 00:10:01,090 +So the demos I'm gonna +do today, the two demos, + +231 +00:10:01,090 --> 00:10:02,719 +one, we're gonna go back to Enroute, + +232 +00:10:02,719 --> 00:10:04,478 +and in the FilterFlights, + +233 +00:10:04,478 --> 00:10:07,990 +we choose the destination +airport right now from a Picker, + +234 +00:10:07,990 --> 00:10:09,720 +and we're gonna make it so we can choose + +235 +00:10:09,720 --> 00:10:11,708 +that destination airport from a map, + +236 +00:10:11,708 --> 00:10:15,450 +an actual map, or an +Apple Maps-like thing. + +237 +00:10:15,450 --> 00:10:19,574 +Right in our UI we can +pick the airport that way. + +238 +00:10:19,574 --> 00:10:24,097 +And that's going to be +essentially a UIViewRepresentable + +239 +00:10:24,097 --> 00:10:25,874 +because the map, it's just gonna be + +240 +00:10:25,874 --> 00:10:28,916 +a UIKit map called an MKMapView. + +241 +00:10:28,916 --> 00:10:30,751 +It's actually not even in UIKit. + +242 +00:10:30,751 --> 00:10:32,287 +It's in something called MapKit + +243 +00:10:32,287 --> 00:10:37,069 +which is really part of +the whole UIKit ecosystem. + +244 +00:10:37,069 --> 00:10:39,117 +And then the second feature we're gonna do + +245 +00:10:39,117 --> 00:10:40,626 +is we're gonna go into EmojiArt + +246 +00:10:40,626 --> 00:10:42,879 +and make it so that the background image + +247 +00:10:42,879 --> 00:10:45,930 +instead of being dragged +in or copy and paste, + +248 +00:10:45,930 --> 00:10:47,799 +we're gonna add another +way to do it which is + +249 +00:10:47,799 --> 00:10:49,386 +you can take a picture with your camera + +250 +00:10:49,386 --> 00:10:51,912 +or just get a photo out +of your photo library + +251 +00:10:51,912 --> 00:10:53,840 +and use that as the background. + +252 +00:10:53,840 --> 00:10:58,602 +Now this is going to use a +UIViewControllerRepresentable + +253 +00:10:58,602 --> 00:11:01,040 +because getting a picture from the camera + +254 +00:11:01,040 --> 00:11:03,722 +involves putting up one +of these MVC things, + +255 +00:11:03,722 --> 00:11:06,401 +these Controllers that +controls all the Views + +256 +00:11:06,401 --> 00:11:09,268 +that are in the UI that gets +a picture from the camera + +257 +00:11:09,268 --> 00:11:11,500 +and same thing with the photo library. + +258 +00:11:11,500 --> 00:11:14,685 +So this is a little slightly +different kind of integration, + +259 +00:11:14,685 --> 00:11:17,467 +this ViewController integration. + +260 +00:11:17,467 --> 00:11:20,520 +Now I'm just gonna give a caveat +before we start this demo. + +261 +00:11:20,520 --> 00:11:22,785 +I'll probably mention it +again in the demo itself. + +262 +00:11:22,785 --> 00:11:25,173 +This is not an awesomely implemented + +263 +00:11:25,173 --> 00:11:26,743 +feature for us in EmojiArt + +264 +00:11:26,743 --> 00:11:28,006 +because we take the picture + +265 +00:11:28,006 --> 00:11:30,047 +from the camera or the photo library + +266 +00:11:30,047 --> 00:11:32,928 +and we just drop it into our filesystem + +267 +00:11:32,928 --> 00:11:35,468 +and store it as a URL in our EmojiArt + +268 +00:11:35,468 --> 00:11:37,739 +like we've been doing so far. + +269 +00:11:37,739 --> 00:11:39,467 +That's actually not +really appropriate here. + +270 +00:11:39,467 --> 00:11:41,770 +You would probably wanna +put the image itself, + +271 +00:11:41,770 --> 00:11:44,792 +the actual JPEG or whatever image data + +272 +00:11:44,792 --> 00:11:47,382 +into your EmojiArt Model, right? + +273 +00:11:47,382 --> 00:11:49,420 +Store it there so that if you took + +274 +00:11:49,420 --> 00:11:50,473 +that EmojiArt document someday + +275 +00:11:50,473 --> 00:11:51,890 +and you moved it to another device, + +276 +00:11:51,890 --> 00:11:53,001 +it would actually work, + +277 +00:11:53,001 --> 00:11:54,861 +whereas really the solution we have + +278 +00:11:54,861 --> 00:11:56,316 +where we just drop it in the filesystem + +279 +00:11:56,316 --> 00:11:58,700 +and grab a URL to it, + +280 +00:11:58,700 --> 00:11:59,901 +it's obviously pointing to something + +281 +00:11:59,901 --> 00:12:04,412 +that's in the sandbox of +this app, that's kinda bogus. + +282 +00:12:04,412 --> 00:12:06,910 +But we're not worried about that, + +283 +00:12:06,910 --> 00:12:08,502 +we're not worried about the background. + +284 +00:12:08,502 --> 00:12:11,443 +We're worried about how +do we put the UIKit UI, + +285 +00:12:12,660 --> 00:12:16,640 +the Controller that gets +images from the camera + +286 +00:12:16,640 --> 00:12:17,473 +or the photo library, + +287 +00:12:17,473 --> 00:12:19,780 +how do we get that to work in our SwiftUI + +288 +00:12:19,780 --> 00:12:21,563 +so we can get the image out of it. + +289 +00:12:22,648 --> 00:12:23,674 +So that's it. + +290 +00:12:23,674 --> 00:12:25,927 +So let's dive right in. + +291 +00:12:25,927 --> 00:12:30,063 +Enjoy the very last demo of the year. + +292 +00:12:31,478 --> 00:12:34,173 +The first of the two demos +here is going to be showing + +293 +00:12:34,173 --> 00:12:38,953 +how to integrate a UIKit +View into a SwiftUI View. + +294 +00:12:38,953 --> 00:12:42,230 +And the UIKit View we're +gonna do is MapView. + +295 +00:12:42,230 --> 00:12:46,504 +Actually it's in its own +little framework called MapKit, + +296 +00:12:46,504 --> 00:12:49,970 +but it is a UIKit-style View. + +297 +00:12:49,970 --> 00:12:53,408 +And what I essentially wanna +do is here in my FilterFlights + +298 +00:12:53,408 --> 00:12:55,253 +where we're choosing our destination, + +299 +00:12:55,253 --> 00:12:57,542 +origin, and our airline, et cetera, + +300 +00:12:57,542 --> 00:12:58,687 +for the destination, + +301 +00:12:58,687 --> 00:12:59,579 +I'm still gonna allow you + +302 +00:12:59,579 --> 00:13:01,318 +to pick your destination via Picker, + +303 +00:13:01,318 --> 00:13:05,701 +but I also want you to be +able to pick it via a MapView + +304 +00:13:05,701 --> 00:13:09,570 +that we create by using the UIKit MapView. + +305 +00:13:10,466 --> 00:13:13,579 +Let's put this in its own Section here. + +306 +00:13:13,579 --> 00:13:16,483 +And we'll put the other +things in their own Section. + +307 +00:13:16,483 --> 00:13:19,180 +I could imagine that quite easily + +308 +00:13:19,180 --> 00:13:22,303 +wanting to use this map +also for the origin later. + +309 +00:13:22,303 --> 00:13:23,940 +We're gonna focus on just doing it + +310 +00:13:23,940 --> 00:13:25,723 +for the destination for this demo. + +311 +00:13:26,723 --> 00:13:30,338 +So what is this MapView thing right here? + +312 +00:13:30,338 --> 00:13:32,151 +It's going to be one of these + +313 +00:13:32,151 --> 00:13:34,489 +UIViewRepresentables we talked about. + +314 +00:13:34,489 --> 00:13:35,930 +Let's go create that. + +315 +00:13:35,930 --> 00:13:37,463 +File, New, File. + +316 +00:13:38,542 --> 00:13:40,296 +It is a SwiftUI View + +317 +00:13:40,296 --> 00:13:43,208 +but since it's going to +be a UIViewRepresentable, + +318 +00:13:43,208 --> 00:13:44,727 +it's not going to have var body, + +319 +00:13:44,727 --> 00:13:49,158 +that's gonna be implemented +by UIViewRepresentable for us. + +320 +00:13:49,158 --> 00:13:49,991 +Let's go here. + +321 +00:13:49,991 --> 00:13:51,650 +I'm gonna call this my MapView. + +322 +00:13:54,229 --> 00:13:56,304 +And when we're doing our MapView, + +323 +00:13:56,304 --> 00:14:00,847 +we're going to have to import +more than just SwiftUI, + +324 +00:14:00,847 --> 00:14:03,799 +we're gonna have to also import UIKit + +325 +00:14:03,799 --> 00:14:06,447 +and also import MapKit. + +326 +00:14:07,667 --> 00:14:10,573 +A lot of imports to do right there. + +327 +00:14:11,541 --> 00:14:14,562 +This struct called MapView, + +328 +00:14:14,562 --> 00:14:18,361 +it is a View but it's +even more than a View, + +329 +00:14:18,361 --> 00:14:19,713 +it's a UIViewRepresentable. + +330 +00:14:20,989 --> 00:14:23,976 +This is a different protocol right here + +331 +00:14:23,976 --> 00:14:25,734 +that inherits from the View protocol, + +332 +00:14:25,734 --> 00:14:27,605 +but it has a bunch of other stuff in it + +333 +00:14:27,605 --> 00:14:31,562 +that allows us to do this +integration with UIKit obviously. + +334 +00:14:31,562 --> 00:14:34,088 +And we see that we do not conform + +335 +00:14:34,088 --> 00:14:36,290 +to the protocol UIViewRepresentable + +336 +00:14:36,290 --> 00:14:37,947 +'cause we have to put those functions + +337 +00:14:37,947 --> 00:14:40,960 +that I was showing you in the slides + +338 +00:14:40,960 --> 00:14:45,960 +like func makeUIView +given a certain context + +339 +00:14:47,319 --> 00:14:51,338 +that returns the UIKit +View that we want to do. + +340 +00:14:51,338 --> 00:14:52,393 +And what are we doing here? + +341 +00:14:52,393 --> 00:14:54,203 +We're doing MKMapView. + +342 +00:14:55,144 --> 00:14:59,036 +This is the UIKit View +we're trying to build. + +343 +00:14:59,036 --> 00:15:01,162 +In fact I'm gonna build it here. + +344 +00:15:01,162 --> 00:15:03,863 +Okay, that View equals MKMapView. + +345 +00:15:05,508 --> 00:15:07,508 +And then I'm gonna return the mkMapView. + +346 +00:15:09,407 --> 00:15:11,834 +I'll be doing a little more +to create it here in a second. + +347 +00:15:11,834 --> 00:15:15,647 +And we also have that func updateUIView + +348 +00:15:15,647 --> 00:15:18,663 +which gives us the UIView back, + +349 +00:15:18,663 --> 00:15:23,663 +this MKMapView and also that context. + +350 +00:15:24,030 --> 00:15:26,970 +And inside here we can +do whatever we need to do + +351 +00:15:26,970 --> 00:15:28,824 +to keep this MapView up to date + +352 +00:15:28,824 --> 00:15:30,960 +as our SwiftUI goes through + +353 +00:15:30,960 --> 00:15:35,073 +its normal reactive redrawing mechanisms. + +354 +00:15:35,073 --> 00:15:38,842 +And then we have this func makeCoordinator + +355 +00:15:38,842 --> 00:15:41,873 +which returns something +that is a don't care + +356 +00:15:41,873 --> 00:15:45,167 +which I'm gonna call Coordinator, +this type right here. + +357 +00:15:45,167 --> 00:15:47,301 +I'm gonna make that a little nested class + +358 +00:15:47,301 --> 00:15:51,089 +inside my struct here called Coordinator. + +359 +00:15:51,089 --> 00:15:54,415 +And it's going to be +my MapView's delegate. + +360 +00:15:54,415 --> 00:15:56,750 +This MapView has one of those things + +361 +00:15:56,750 --> 00:15:57,958 +we were talking about, a delegate. + +362 +00:15:57,958 --> 00:16:01,660 +So to be a delegate, it +has to also be an NSObject, + +363 +00:16:01,660 --> 00:16:06,660 +and it has to implement the +MKMapViewDelegate protocol. + +364 +00:16:07,631 --> 00:16:12,350 +All the delegates in +UIKit always are classes + +365 +00:16:12,350 --> 00:16:15,276 +that inherit from this +base class NSObject. + +366 +00:16:15,276 --> 00:16:17,514 +So I'm gonna do the same thing here + +367 +00:16:17,514 --> 00:16:19,775 +in our SwiftUI compatibility + +368 +00:16:19,775 --> 00:16:22,890 +as it's done in normal UIKit, + +369 +00:16:22,890 --> 00:16:25,544 +make a delegate that +inherits from NSObject + +370 +00:16:25,544 --> 00:16:26,755 +and implements these methods. + +371 +00:16:26,755 --> 00:16:30,299 +Now it turns out none of the +methods in here are required, + +372 +00:16:30,299 --> 00:16:32,730 +but we're actually going to need + +373 +00:16:32,730 --> 00:16:34,139 +a couple of them to make this work, + +374 +00:16:34,139 --> 00:16:36,530 +but that's why I'm not +getting any complaints here + +375 +00:16:36,530 --> 00:16:38,927 +that this protocol is not +implemented or something like that + +376 +00:16:38,927 --> 00:16:41,505 +because it has 10 or 12 methods + +377 +00:16:41,505 --> 00:16:43,654 +all of which are not required. + +378 +00:16:43,654 --> 00:16:45,490 +So how are we gonna make our Coordinator? + +379 +00:16:45,490 --> 00:16:46,813 +I'm just gonna literally say + +380 +00:16:46,813 --> 00:16:48,501 +make me one of these Coordinators + +381 +00:16:48,501 --> 00:16:50,830 +that I just defined down here. + +382 +00:16:50,830 --> 00:16:51,663 +This is just a class. + +383 +00:16:51,663 --> 00:16:55,030 +I'm just making a class +and I'm returning it here. + +384 +00:16:55,030 --> 00:16:59,229 +You don't have to say return +but that's what I'm doing. + +385 +00:16:59,229 --> 00:17:01,652 +This is the basic structure + +386 +00:17:01,652 --> 00:17:05,523 +of a UIViewRepresentable right here. + +387 +00:17:05,523 --> 00:17:08,616 +The only thing is we wanna +hook up our Coordinator + +388 +00:17:08,616 --> 00:17:11,346 +which is this delegate to our MapView. + +389 +00:17:11,346 --> 00:17:14,231 +We're gonna do that right +here by saying mkMapView, + +390 +00:17:14,231 --> 00:17:17,387 +your delegate is our Coordinator. + +391 +00:17:17,387 --> 00:17:19,883 +And we get the Coordinator +out of our context. + +392 +00:17:19,883 --> 00:17:22,060 +This is not where we +create the Coordinator. + +393 +00:17:22,060 --> 00:17:24,520 +It gets created down here inside this. + +394 +00:17:24,520 --> 00:17:29,043 +So if we wanted, we just +say context.coordinator. + +395 +00:17:31,482 --> 00:17:32,660 +Let's go back to our FilterFlights. + +396 +00:17:32,660 --> 00:17:37,101 +And if we build actually, this succeeds. + +397 +00:17:37,101 --> 00:17:40,720 +It's able to build because we +made a thing called MapView. + +398 +00:17:40,720 --> 00:17:45,557 +This is a normal SwiftUI View +called MapView right here. + +399 +00:17:45,557 --> 00:17:46,853 +And if we run, + +400 +00:17:48,294 --> 00:17:50,602 +go to our Filter, + +401 +00:17:50,602 --> 00:17:51,489 +there it is, + +402 +00:17:51,489 --> 00:17:53,100 +there's our map right there. + +403 +00:17:53,100 --> 00:17:54,680 +You can't see much. + +404 +00:17:54,680 --> 00:17:55,681 +It's still too small. + +405 +00:17:55,681 --> 00:17:58,378 +So why don't we make this a lot bigger? + +406 +00:17:58,378 --> 00:18:01,720 +Maybe have it be, I mean at least + +407 +00:18:01,720 --> 00:18:04,095 +maybe three or 400 points high. + +408 +00:18:04,095 --> 00:18:06,058 +The width is fine but you wanna make sure + +409 +00:18:06,058 --> 00:18:08,001 +that it's at least three +or 400 points high. + +410 +00:18:08,001 --> 00:18:10,937 +So I'm gonna go down here and +say .frame(minHeight: 400). + +411 +00:18:13,930 --> 00:18:16,373 +Let's see what that looks like. + +412 +00:18:17,665 --> 00:18:18,746 +Go to Filter. + +413 +00:18:18,746 --> 00:18:19,851 +Whoa! + +414 +00:18:19,851 --> 00:18:22,260 +That looks a lot better +when you can see it. + +415 +00:18:22,260 --> 00:18:23,565 +And there is our map. + +416 +00:18:23,565 --> 00:18:25,835 +Now of course none of these airports + +417 +00:18:25,835 --> 00:18:28,365 +that we have here are +showing up on the map, + +418 +00:18:28,365 --> 00:18:30,697 +no kind of markers or anything for it. + +419 +00:18:30,697 --> 00:18:34,677 +That's because we don't do +anything to put them on there. + +420 +00:18:34,677 --> 00:18:37,333 +So let's learn a little bit about MapKit. + +421 +00:18:37,333 --> 00:18:41,003 +How does one put little markings on here + +422 +00:18:41,003 --> 00:18:42,590 +to represent these airports? + +423 +00:18:42,590 --> 00:18:45,287 +Well, MapKit is actually pretty flexible + +424 +00:18:45,287 --> 00:18:47,020 +and it uses protocols. + +425 +00:18:47,020 --> 00:18:49,433 +It has a protocol called MKAnnotation. + +426 +00:18:50,320 --> 00:18:54,014 +And any object that +implements MKAnnotation + +427 +00:18:54,014 --> 00:18:55,616 +can be put on a map. + +428 +00:18:55,616 --> 00:18:58,731 +So all you need to do to +put an object on the map + +429 +00:18:58,731 --> 00:19:01,990 +is implement MKAnnotation for that object. + +430 +00:19:01,990 --> 00:19:05,506 +So what kind of objects do we +want on our map right here? + +431 +00:19:05,506 --> 00:19:08,015 +Well, we want Airports. + +432 +00:19:08,015 --> 00:19:09,261 +So here's our Airport. + +433 +00:19:09,261 --> 00:19:11,852 +This is our Core Data object +that does the Airport. + +434 +00:19:11,852 --> 00:19:15,916 +I'm just going to add an extension to it + +435 +00:19:15,916 --> 00:19:19,931 +that implements this +MKAnnotation protocol. + +436 +00:19:19,931 --> 00:19:22,178 +And we need to import MapKit here + +437 +00:19:22,178 --> 00:19:26,070 +because MKAnnotation is inside MapKit. + +438 +00:19:26,070 --> 00:19:30,451 +Now what is required of +this MKAnnotation protocol? + +439 +00:19:30,451 --> 00:19:33,070 +Let's go ahead and even +use our "Fix it" here. + +440 +00:19:33,070 --> 00:19:35,313 +We can see the type +Airport does not confirm. + +441 +00:19:35,313 --> 00:19:37,396 +But we can add protocol stubs + +442 +00:19:37,396 --> 00:19:40,779 +that will add the required +methods here, "Fix". + +443 +00:19:40,779 --> 00:19:41,830 +There it is. + +444 +00:19:41,830 --> 00:19:42,708 +Just this one var. + +445 +00:19:42,708 --> 00:19:44,562 +If you implement just this one var, + +446 +00:19:44,562 --> 00:19:48,101 +then you too can be an MKAnnotation. + +447 +00:19:48,101 --> 00:19:50,777 +And what is this var coordinate? + +448 +00:19:50,777 --> 00:19:51,900 +What's its type? + +449 +00:19:51,900 --> 00:19:52,754 +What's it returning? + +450 +00:19:52,754 --> 00:19:55,240 +It's a CLLocationCoordinate2D. + +451 +00:19:55,240 --> 00:19:58,056 +This is latitude and longitude. + +452 +00:19:58,056 --> 00:20:03,056 +And luckily, Airports, we look +at our data model over here. + +453 +00:20:03,360 --> 00:20:05,827 +Let's do the version here. + +454 +00:20:05,827 --> 00:20:08,200 +You can see we have a +latitude and longitude + +455 +00:20:08,200 --> 00:20:09,970 +that we got from FlightAware. + +456 +00:20:09,970 --> 00:20:13,750 +So we are absolutely ready +over here to be one of these. + +457 +00:20:13,750 --> 00:20:17,060 +I'm just going to return, +creating a CLLocationCoordinate2D + +458 +00:20:19,536 --> 00:20:22,676 +from a latitude which is our latitude, + +459 +00:20:22,676 --> 00:20:25,047 +this is just a var in the database, + +460 +00:20:25,047 --> 00:20:28,477 +and longitude, this is our other var. + +461 +00:20:28,477 --> 00:20:29,433 +That's it. + +462 +00:20:29,433 --> 00:20:33,055 +Look, it compiles and allows +us to be an MKAnnotation. + +463 +00:20:33,055 --> 00:20:34,455 +Now MKAnnotation, + +464 +00:20:34,455 --> 00:20:39,455 +again it's Objective-C +version of a protocol. + +465 +00:20:39,571 --> 00:20:41,323 +This is the only required var + +466 +00:20:41,323 --> 00:20:44,081 +but it has a couple other vars +that I'm gonna throw in here. + +467 +00:20:44,081 --> 00:20:47,034 +And one of these vars is called title. + +468 +00:20:47,034 --> 00:20:49,030 +It's an Optional String. + +469 +00:20:49,030 --> 00:20:50,106 +And it's something that + +470 +00:20:50,106 --> 00:20:51,861 +if you click on something in the map, + +471 +00:20:51,861 --> 00:20:53,740 +it'll show you this title. + +472 +00:20:53,740 --> 00:20:55,891 +So I'm gonna have this be +the name of the Airport. + +473 +00:20:55,891 --> 00:20:59,646 +If that's not set, we'll +use the KSFO or whatever. + +474 +00:20:59,646 --> 00:21:02,012 +And then it also has +another one called subtitle + +475 +00:21:02,012 --> 00:21:03,729 +which it'll also show in the call-out + +476 +00:21:03,729 --> 00:21:05,709 +that comes if you click on something. + +477 +00:21:05,709 --> 00:21:06,853 +And then we'll put the location + +478 +00:21:06,853 --> 00:21:09,913 +like San Jose, California +or whatever in there. + +479 +00:21:10,920 --> 00:21:13,380 +So Airports are now MKAnnotations, + +480 +00:21:13,380 --> 00:21:17,870 +and that means that they can +be put anywhere on this map. + +481 +00:21:17,870 --> 00:21:20,533 +If we drop Airport on this map, + +482 +00:21:20,533 --> 00:21:23,317 +it's gonna have some sort of +little representation of it. + +483 +00:21:23,317 --> 00:21:26,763 +I'm gonna show you how to +do that in a second as well. + +484 +00:21:28,351 --> 00:21:31,505 +We need to have our MapView right here + +485 +00:21:31,505 --> 00:21:34,478 +have some sort of var +that you can pass into it. + +486 +00:21:34,478 --> 00:21:39,168 +I'm gonna make it a let even +which is the annotations. + +487 +00:21:39,168 --> 00:21:42,500 +It's just an Array of +those MKAnnotation things. + +488 +00:21:42,500 --> 00:21:43,644 +So this could be Airport, + +489 +00:21:43,644 --> 00:21:46,352 +anything else that +implements MKAnnotation. + +490 +00:21:46,352 --> 00:21:48,178 +And when we make our View, + +491 +00:21:48,178 --> 00:21:50,482 +in addition to setting the delegate here, + +492 +00:21:50,482 --> 00:21:55,423 +I'm gonna add these +annotations to the map. + +493 +00:21:57,425 --> 00:21:58,390 +That's it. + +494 +00:21:58,390 --> 00:22:01,200 +That's all we have to do +to make them be on the map. + +495 +00:22:01,200 --> 00:22:03,077 +Now the only problem is the map, + +496 +00:22:03,077 --> 00:22:04,982 +it has no idea how to draw them. + +497 +00:22:04,982 --> 00:22:07,559 +It doesn't know are you +drawing some sort of pin + +498 +00:22:07,559 --> 00:22:10,369 +or some sort of a marker or a custom View + +499 +00:22:10,369 --> 00:22:12,414 +or what are you doing to draw it? + +500 +00:22:12,414 --> 00:22:15,430 +And how these annotations +get drawn on a map + +501 +00:22:15,430 --> 00:22:17,428 +is actually controlled by this delegate. + +502 +00:22:17,428 --> 00:22:19,542 +So we're gonna see our first ever + +503 +00:22:19,542 --> 00:22:21,150 +delegate method from UIKit. + +504 +00:22:21,150 --> 00:22:23,930 +And the one we want here is called + +505 +00:22:23,930 --> 00:22:26,145 +mapView ViewFor annotation. + +506 +00:22:26,145 --> 00:22:27,003 +Let's see if we can find it. + +507 +00:22:27,003 --> 00:22:28,106 +Look at all of these. + +508 +00:22:28,106 --> 00:22:31,170 +These are all MapView +delegate functions right here, + +509 +00:22:31,170 --> 00:22:33,259 +didSelect something, didDeselect, + +510 +00:22:33,259 --> 00:22:35,875 +the region we're showing +in the map change. + +511 +00:22:35,875 --> 00:22:39,679 +I'm looking for the one +which is ViewFor annotation. + +512 +00:22:39,679 --> 00:22:41,079 +It's right here. + +513 +00:22:41,079 --> 00:22:42,622 +And this is just returning + +514 +00:22:42,622 --> 00:22:44,424 +something called an MKAnnotationView + +515 +00:22:44,424 --> 00:22:48,264 +which is a UIKit View +that shows annotations. + +516 +00:22:48,264 --> 00:22:51,057 +And all it's doing is +getting the right one + +517 +00:22:51,057 --> 00:22:52,627 +for a given annotation, + +518 +00:22:52,627 --> 00:22:54,189 +in our case these are Airports, + +519 +00:22:54,189 --> 00:22:56,870 +so just creating a View for the Airports. + +520 +00:22:56,870 --> 00:22:59,942 +Now we're not here to learn MapKit + +521 +00:22:59,942 --> 00:23:01,570 +so I'm just going to show you + +522 +00:23:01,570 --> 00:23:04,912 +how one does this to +create this little View. + +523 +00:23:04,912 --> 00:23:06,570 +And I'm gonna use a pin. + +524 +00:23:06,570 --> 00:23:07,961 +I can also do markers + +525 +00:23:07,961 --> 00:23:10,436 +which are kind of a new look of the map. + +526 +00:23:10,436 --> 00:23:15,317 +You ask the mapView to dequeue +a ReusableAnnotationView + +527 +00:23:15,317 --> 00:23:17,141 +with the identifier, + +528 +00:23:17,141 --> 00:23:18,950 +and we can use any +identifier we want here, + +529 +00:23:18,950 --> 00:23:21,513 +I'm gonna just call mine +"MapViewAnnotation". + +530 +00:23:22,922 --> 00:23:25,754 +And if that comes back +nil, I can't reuse one. + +531 +00:23:25,754 --> 00:23:29,203 +This is reusing one of +those pins or whatever. + +532 +00:23:29,203 --> 00:23:31,773 +Now I'm gonna create my +own, MKPinAnnotationView. + +533 +00:23:33,450 --> 00:23:34,700 +That's the one that looks like a pin. + +534 +00:23:34,700 --> 00:23:38,370 +And it takes the annotation +like our airport or whatever + +535 +00:23:38,370 --> 00:23:41,550 +and it also wants that +reuseIdentifier again, + +536 +00:23:41,550 --> 00:23:42,533 +the same thing here. + +537 +00:23:42,533 --> 00:23:44,182 +I should probably create +a constant for that + +538 +00:23:44,182 --> 00:23:46,759 +but I'll just quickly type it in here. + +539 +00:23:46,759 --> 00:23:50,708 +And that is creating a +little PinAnnotationView. + +540 +00:23:50,708 --> 00:23:53,180 +The newer one is called +a MarkerAnnotationView. + +541 +00:23:53,180 --> 00:23:55,022 +We could use that but +I'm gonna use the pin. + +542 +00:23:55,022 --> 00:23:56,918 +I kinda like the call-outs on the pin. + +543 +00:23:56,918 --> 00:23:58,980 +And speaking of which I'm also gonna call + +544 +00:23:58,980 --> 00:24:01,758 +something on that View +called canShowCallout, + +545 +00:24:01,758 --> 00:24:03,440 +set that to be true. + +546 +00:24:03,440 --> 00:24:05,240 +I'm gonna return this View. + +547 +00:24:05,240 --> 00:24:08,734 +And this is how the +MapView knows what View + +548 +00:24:08,734 --> 00:24:12,833 +am I supposed to use to +draw a certain annotation. + +549 +00:24:14,377 --> 00:24:16,578 +Now the last thing we +need to do of course is + +550 +00:24:16,578 --> 00:24:18,148 +when we create our MapView, + +551 +00:24:18,148 --> 00:24:21,967 +we need to pass the +annotations we want in, + +552 +00:24:21,967 --> 00:24:26,200 +and this has to be an +Array of MKAnnotations. + +553 +00:24:26,200 --> 00:24:28,226 +Well, Airports are MKAnnotations, + +554 +00:24:28,226 --> 00:24:31,326 +so this could be an +Array of Airports, right? + +555 +00:24:31,326 --> 00:24:35,523 +So let's do our airports.sorted. + +556 +00:24:35,523 --> 00:24:39,515 +airport is this thing +we're fetching all of. + +557 +00:24:39,515 --> 00:24:41,100 +Right here we got a FetchedResults. + +558 +00:24:41,100 --> 00:24:44,509 +And I'm just taking these +FetchedResults and sorting them + +559 +00:24:44,509 --> 00:24:46,492 +so that we'd get our annotations sorted. + +560 +00:24:46,492 --> 00:24:47,714 +It really doesn't matter. + +561 +00:24:47,714 --> 00:24:50,240 +I could also say Array(airports). + +562 +00:24:50,240 --> 00:24:52,866 +I'm doing this because +this takes an Array, + +563 +00:24:52,866 --> 00:24:55,230 +and airport is a FetchedResult, + +564 +00:24:55,230 --> 00:24:58,347 +so again which is a collection +but not quite an Array. + +565 +00:24:58,347 --> 00:25:01,350 +So just sorting them +turns them into an Array. + +566 +00:25:01,350 --> 00:25:05,434 +I could just say Array(airports) as well. + +567 +00:25:05,434 --> 00:25:08,653 +So let's see if this is working. + +568 +00:25:08,653 --> 00:25:11,984 +Hopefully now when we +go to our filter, wow! + +569 +00:25:11,984 --> 00:25:15,343 +I see all these airports +right here now appear here. + +570 +00:25:15,343 --> 00:25:17,095 +You can see them overseas. + +571 +00:25:17,095 --> 00:25:18,340 +And they're really cool, + +572 +00:25:18,340 --> 00:25:20,443 +these pins if you tap on them, + +573 +00:25:20,443 --> 00:25:23,646 +it shows you that title +and subtile that we set. + +574 +00:25:23,646 --> 00:25:25,590 +Title and subtitle. + +575 +00:25:25,590 --> 00:25:27,434 +Title and subtitle. + +576 +00:25:27,434 --> 00:25:31,150 +Big advancement already right there. + +577 +00:25:31,150 --> 00:25:35,540 +The only thing here is when +I go and choose Boston, + +578 +00:25:35,540 --> 00:25:38,471 +I want this to kinda zoom in on Boston. + +579 +00:25:38,471 --> 00:25:43,044 +And also if I were to click +on Houston, Texas here, + +580 +00:25:43,044 --> 00:25:45,294 +I want this to change to Houston. + +581 +00:25:45,294 --> 00:25:47,267 +So we have a little bit of work to do + +582 +00:25:47,267 --> 00:25:49,723 +to hook up this selection up here + +583 +00:25:49,723 --> 00:25:52,586 +to whatever is selected and zoomed in on + +584 +00:25:52,586 --> 00:25:54,737 +in our map right here. + +585 +00:25:54,737 --> 00:25:56,528 +So let's start doing the zoom in. + +586 +00:25:56,528 --> 00:25:59,498 +How am I gonna zoom in on +whatever is selected here? + +587 +00:25:59,498 --> 00:26:02,655 +That's pretty straightforward +to do actually. + +588 +00:26:02,655 --> 00:26:07,655 +Remember that every time our +SwiftUI update passes happen, + +589 +00:26:07,741 --> 00:26:09,885 +we get a chance to update this View. + +590 +00:26:09,885 --> 00:26:13,484 +So I'm gonna put a little +var here called my selection + +591 +00:26:13,484 --> 00:26:14,810 +which is gonna be an MKAnnotation. + +592 +00:26:14,810 --> 00:26:16,516 +I'll make it Optional + +593 +00:26:16,516 --> 00:26:19,172 +'cause you don't have to select +an annotation if you want. + +594 +00:26:19,172 --> 00:26:21,838 +But if you do, then when I'm updating, + +595 +00:26:21,838 --> 00:26:26,838 +every time I draw, I'm gonna +zoom in to show this selection. + +596 +00:26:27,112 --> 00:26:31,660 +Say here if I can let +annotation equal the selection, + +597 +00:26:31,660 --> 00:26:33,727 +so you have chosen one, + +598 +00:26:33,727 --> 00:26:35,245 +then I'm gonna do this thing + +599 +00:26:35,245 --> 00:26:39,386 +in the MapView called setRegion. + +600 +00:26:39,386 --> 00:26:41,923 +And setRegion takes an MKCoordinateRegion. + +601 +00:26:44,332 --> 00:26:46,784 +An MKCoordinateRegion takes a center + +602 +00:26:46,784 --> 00:26:50,504 +which is gonna be that +annotation's coordinates, right? + +603 +00:26:50,504 --> 00:26:52,880 +That's this thing we +implemented right here + +604 +00:26:52,880 --> 00:26:55,453 +for airport to CLLocationCoordinate2D. + +605 +00:26:55,453 --> 00:26:58,594 +That's saying where is this annotation? + +606 +00:26:58,594 --> 00:27:01,134 +That is the selection right there. + +607 +00:27:01,134 --> 00:27:03,645 +And it also takes a span, + +608 +00:27:03,645 --> 00:27:06,240 +and this span is an +object we're gonna create. + +609 +00:27:06,240 --> 00:27:09,585 +This is how much to zoom in essentially. + +610 +00:27:09,585 --> 00:27:13,647 +And we can also say that yes, +we want it animated as well. + +611 +00:27:13,647 --> 00:27:15,439 +So what is this span? + +612 +00:27:15,439 --> 00:27:17,630 +When I zoom in on something, + +613 +00:27:17,630 --> 00:27:20,780 +I want it to be kind of a town-sized View. + +614 +00:27:20,780 --> 00:27:23,990 +So I'm gonna call this span town. + +615 +00:27:23,990 --> 00:27:26,306 +It's gonna be the span +that's approximately a town. + +616 +00:27:26,306 --> 00:27:29,514 +So what is a span that's +approximately a town? + +617 +00:27:29,514 --> 00:27:31,060 +Well, it's an MKCoordinateSpan + +618 +00:27:32,727 --> 00:27:35,500 +which just specifies the latitudeDelta, + +619 +00:27:35,500 --> 00:27:37,278 +we're gonna do .1 degrees, + +620 +00:27:37,278 --> 00:27:39,507 +and the longitude, .1. + +621 +00:27:39,507 --> 00:27:41,966 +So .1 degrees of latitude and longitude + +622 +00:27:41,966 --> 00:27:44,317 +is about the size of a town. + +623 +00:27:44,317 --> 00:27:46,199 +It's a little smaller than a city + +624 +00:27:46,199 --> 00:27:48,656 +but it's bigger than like +a little neighborhood. + +625 +00:27:48,656 --> 00:27:50,800 +This is kind of a good size to zoom in on + +626 +00:27:50,800 --> 00:27:54,828 +if you're zooming in on some annotation. + +627 +00:27:54,828 --> 00:27:56,910 +And this is gonna happen every time + +628 +00:27:56,910 --> 00:28:00,665 +that this MapView gets +updated in the SwiftUI, + +629 +00:28:00,665 --> 00:28:03,438 +reactive UI updating passes. + +630 +00:28:03,438 --> 00:28:07,122 +We're going to re-zoom +to show our selection. + +631 +00:28:07,122 --> 00:28:09,137 +So let's go over here +and set our selection. + +632 +00:28:09,137 --> 00:28:10,826 +Here's where we'll create our MapView. + +633 +00:28:10,826 --> 00:28:13,240 +We'll add this extra +argument, the selection. + +634 +00:28:13,240 --> 00:28:14,738 +And what is the selection? + +635 +00:28:14,738 --> 00:28:18,169 +Well, it's just our +draft's destination, right? + +636 +00:28:18,169 --> 00:28:20,371 +This draft is our FlightSearch. + +637 +00:28:20,371 --> 00:28:22,918 +This is what we're kind of filtering for. + +638 +00:28:22,918 --> 00:28:26,173 +And the destination is the +destination Airport inside draft. + +639 +00:28:26,173 --> 00:28:27,006 +It's the exact same thing + +640 +00:28:27,006 --> 00:28:30,120 +we're showing as our +Pickers thing right here. + +641 +00:28:30,120 --> 00:28:31,823 +Let's see. + +642 +00:28:34,790 --> 00:28:35,821 +Hit Filter. + +643 +00:28:35,821 --> 00:28:37,186 +Hopefully, yeah! + +644 +00:28:37,186 --> 00:28:38,176 +San Francisco. + +645 +00:28:38,176 --> 00:28:40,410 +This is San Francisco International. + +646 +00:28:40,410 --> 00:28:41,260 +Let's pick something else. + +647 +00:28:41,260 --> 00:28:42,401 +How about Boston? + +648 +00:28:42,401 --> 00:28:44,957 +Oop, zoom in over, there's Boston. + +649 +00:28:44,957 --> 00:28:47,197 +Maybe pick Bob Hope, Burbank. + +650 +00:28:47,197 --> 00:28:49,177 +Back to Bob Hope, there it is. + +651 +00:28:49,177 --> 00:28:51,679 +Now we can still zoom back out right here + +652 +00:28:51,679 --> 00:28:53,625 +and pick other airports. + +653 +00:28:53,625 --> 00:28:55,690 +The problem is though when we pick them, + +654 +00:28:55,690 --> 00:28:57,643 +it's not updating here. + +655 +00:28:57,643 --> 00:28:59,001 +When I'm picking this, it's nice. + +656 +00:28:59,001 --> 00:29:00,844 +It's telling me it's +San Diego International. + +657 +00:29:00,844 --> 00:29:02,175 +But when I pick it here, + +658 +00:29:02,175 --> 00:29:06,688 +I mean choose this, go to that place. + +659 +00:29:06,688 --> 00:29:09,730 +Now how do we make this go both ways? + +660 +00:29:09,730 --> 00:29:13,365 +This is working well +when we choose Boston. + +661 +00:29:13,365 --> 00:29:16,162 +It goes into here and sets the map. + +662 +00:29:16,162 --> 00:29:18,246 +But how do we make it work the other way + +663 +00:29:18,246 --> 00:29:22,421 +when we click over here +on Newark or whatever, + +664 +00:29:22,421 --> 00:29:24,002 +Connecticut Airport, + +665 +00:29:24,002 --> 00:29:27,494 +it makes that be our destination? + +666 +00:29:27,494 --> 00:29:30,871 +Well, how do we do that in +Views in general, right? + +667 +00:29:30,871 --> 00:29:33,127 +If we have a View and +we can interact with it + +668 +00:29:33,127 --> 00:29:35,319 +and it wants to communicate information + +669 +00:29:35,319 --> 00:29:37,094 +back out to some other View, + +670 +00:29:37,094 --> 00:29:38,242 +what do we do? + +671 +00:29:38,242 --> 00:29:40,630 +We use a Binding. + +672 +00:29:40,630 --> 00:29:44,232 +And this MapView, even though +it's UIViewRepresentable, + +673 +00:29:44,232 --> 00:29:48,140 +it's a View and so we could +have this be a Binding. + +674 +00:29:48,140 --> 00:29:50,913 +This is now a Binding to selection. + +675 +00:29:52,052 --> 00:29:54,840 +Now we will down here go ahead + +676 +00:29:54,840 --> 00:29:57,512 +and have our selection +be updated and all that. + +677 +00:29:57,512 --> 00:30:00,162 +But we have a little bit of +problem first which is that + +678 +00:30:00,162 --> 00:30:04,333 +here we are passing our +selection as an Airport. + +679 +00:30:04,333 --> 00:30:08,532 +So this is not a Binding +to an MKAnnotation, right? + +680 +00:30:08,532 --> 00:30:11,353 +That's what this says, +Binding to MKAnnotation. + +681 +00:30:11,353 --> 00:30:14,178 +This is an Airport. + +682 +00:30:14,178 --> 00:30:16,155 +So how do we do that? + +683 +00:30:16,155 --> 00:30:19,531 +Can we just do dollar sign right there? + +684 +00:30:19,531 --> 00:30:23,677 +No, we can't because draft is @State. + +685 +00:30:23,677 --> 00:30:27,357 +If draft were an ObservedObject, +we could do this. + +686 +00:30:27,357 --> 00:30:29,519 +This would work if this +were an ObservedObject. + +687 +00:30:29,519 --> 00:30:32,027 +But draft is not, draft is State. + +688 +00:30:32,027 --> 00:30:35,150 +And the Binding, the +dollar sign of a State + +689 +00:30:35,150 --> 00:30:37,055 +binds to the entire struct. + +690 +00:30:37,055 --> 00:30:40,834 +You can't bind it to +variables inside the struct. + +691 +00:30:40,834 --> 00:30:44,833 +So how the heck are we +going to pass a Binding + +692 +00:30:44,833 --> 00:30:48,634 +to this Airport inside of this State? + +693 +00:30:48,634 --> 00:30:52,600 +Well, let's create a var +that's called destination. + +694 +00:30:52,600 --> 00:30:56,673 +And it's gonna be a type +Binding to MKAnnotation. + +695 +00:30:58,665 --> 00:31:01,102 +Now as soon as I start +using MKAnnotation here, + +696 +00:31:01,102 --> 00:31:03,790 +better go up here and say import MapKit + +697 +00:31:03,790 --> 00:31:08,790 +or the compiler is not gonna +know what the heck we're doing. + +698 +00:31:08,888 --> 00:31:09,920 +So this is the destination Binding. + +699 +00:31:09,920 --> 00:31:13,867 +And how can we use this +Binding right here? + +700 +00:31:13,867 --> 00:31:17,056 +Just say pass the destination there. + +701 +00:31:17,056 --> 00:31:21,583 +And this when I compile +is gonna work down here. + +702 +00:31:21,583 --> 00:31:25,546 +See, we no longer are +gonna have this thing + +703 +00:31:25,546 --> 00:31:27,904 +where it can't infer +or any errors down here + +704 +00:31:27,904 --> 00:31:31,362 +because I am passing a +Binding to an MKAnnotation + +705 +00:31:31,362 --> 00:31:34,093 +which is exactly what this thing wants, + +706 +00:31:34,093 --> 00:31:36,192 +a Binding to an MKAnnotation. + +707 +00:31:36,192 --> 00:31:37,472 +All we need to do though + +708 +00:31:37,472 --> 00:31:40,009 +is figure out and implement this var. + +709 +00:31:40,009 --> 00:31:45,009 +How do we return a Binding +to an MKAnnotation here? + +710 +00:31:45,470 --> 00:31:48,491 +We need to somehow make an MKAnnotation + +711 +00:31:48,491 --> 00:31:51,414 +that hooks up to this draft's destination. + +712 +00:31:51,414 --> 00:31:52,960 +How are we gonna do that? + +713 +00:31:52,960 --> 00:31:56,246 +Well, we're just going to use +one of Binding's constructors. + +714 +00:31:56,246 --> 00:31:57,573 +You can see it's got a few here. + +715 +00:31:57,573 --> 00:31:59,115 +I'm gonna use this one. + +716 +00:31:59,115 --> 00:32:02,904 +This is almost kind of a +primitive sort of Binding + +717 +00:32:02,904 --> 00:32:05,185 +and it just lets you specify a closure + +718 +00:32:05,185 --> 00:32:06,977 +to get the value of the Binding + +719 +00:32:06,977 --> 00:32:10,216 +and a closure to set +the value of the Binding + +720 +00:32:10,216 --> 00:32:12,131 +which is really getting at the heart + +721 +00:32:12,131 --> 00:32:13,681 +of how Bindings work, right? + +722 +00:32:13,681 --> 00:32:15,612 +Bindings are just getting and setting + +723 +00:32:15,612 --> 00:32:17,702 +some other values somewhere else. + +724 +00:32:17,702 --> 00:32:20,059 +So it makes total sense that +there's a version of Binding + +725 +00:32:20,059 --> 00:32:23,675 +which is just closure to +get and a closure to set. + +726 +00:32:23,675 --> 00:32:27,175 +Now all we need to do is +implement these to get and set + +727 +00:32:27,175 --> 00:32:30,756 +the value of the destination +in our draft State. + +728 +00:32:30,756 --> 00:32:32,439 +Could not be simpler, so let's + +729 +00:32:32,439 --> 00:32:33,680 +Go do this. + +730 +00:32:33,680 --> 00:32:35,159 +It's just a little easier to see + +731 +00:32:35,159 --> 00:32:37,700 +what's going on before we do this. + +732 +00:32:37,700 --> 00:32:39,703 +Let's do the get first. + +733 +00:32:39,703 --> 00:32:42,843 +The get is saying this +is takes no arguments + +734 +00:32:42,843 --> 00:32:45,246 +and returns an MKAnnotation. + +735 +00:32:45,246 --> 00:32:47,946 +Of course because this is a +Binding to an MKAnnotation + +736 +00:32:48,980 --> 00:32:50,530 +so we won't be able to get it there. + +737 +00:32:50,530 --> 00:32:51,448 +So let's do that. + +738 +00:32:51,448 --> 00:32:52,724 +Quite simple here. + +739 +00:32:52,724 --> 00:32:56,820 +We're just going to return +our draft's destination. + +740 +00:32:56,820 --> 00:32:58,680 +Now this is an Airport, + +741 +00:32:58,680 --> 00:33:01,871 +an Airport is definitely an MKAnnotation, + +742 +00:33:01,871 --> 00:33:04,313 +so this is perfectly legal. + +743 +00:33:04,313 --> 00:33:05,800 +I'm also gonna put self in here. + +744 +00:33:05,800 --> 00:33:09,325 +You can return this value. + +745 +00:33:09,325 --> 00:33:11,052 +That's super simple. + +746 +00:33:11,052 --> 00:33:12,486 +What about the set side? + +747 +00:33:12,486 --> 00:33:15,575 +The set is a closure that +takes an MKAnnotation, + +748 +00:33:15,575 --> 00:33:17,110 +an optional MKAnnotation. + +749 +00:33:17,110 --> 00:33:18,439 +It doesn't return anything. + +750 +00:33:18,439 --> 00:33:20,695 +It just sets the value. + +751 +00:33:20,695 --> 00:33:23,596 +Let's have that annotation that it takes + +752 +00:33:23,596 --> 00:33:25,781 +be this argument right here. + +753 +00:33:25,781 --> 00:33:27,754 +We'd like to say something like + +754 +00:33:27,754 --> 00:33:32,277 +self.draft.destination +equals that annotation. + +755 +00:33:32,277 --> 00:33:33,390 +Woo-hoo, we're done! + +756 +00:33:33,390 --> 00:33:35,885 +We'll just do kinda the opposite of this. + +757 +00:33:35,885 --> 00:33:37,937 +But this is not gonna work. + +758 +00:33:37,937 --> 00:33:38,855 +And the reason this doesn't work + +759 +00:33:38,855 --> 00:33:42,576 +is that the type of this is MKAnnotation, + +760 +00:33:42,576 --> 00:33:43,887 +Optional MKAnnotation. + +761 +00:33:43,887 --> 00:33:45,850 +That's its type. + +762 +00:33:45,850 --> 00:33:48,786 +So here we're trying to make an Airport + +763 +00:33:48,786 --> 00:33:51,069 +equal to an MKAnnotation. + +764 +00:33:51,069 --> 00:33:52,609 +That's not gonna work + +765 +00:33:52,609 --> 00:33:55,510 +because an Airport is an MKAnnotation + +766 +00:33:55,510 --> 00:33:58,735 +but not all MKAnnotations are Airports. + +767 +00:33:58,735 --> 00:34:01,652 +So you can't just make +this assignment right here. + +768 +00:34:01,652 --> 00:34:04,180 +This is where we have to do the as, + +769 +00:34:04,180 --> 00:34:06,209 +the type casting that you read about + +770 +00:34:06,209 --> 00:34:08,844 +and we've talked about +briefly a couple of times + +771 +00:34:08,844 --> 00:34:10,534 +maybe in the context of talking about + +772 +00:34:10,534 --> 00:34:13,827 +the old Objective-C Any type. + +773 +00:34:13,827 --> 00:34:17,841 +So I need to capture, I'm gonna +say if I can let an Airport + +774 +00:34:17,841 --> 00:34:22,253 +equal this annotation as an Airport, + +775 +00:34:22,253 --> 00:34:26,588 +and that is conditionally trying +to see if this MKAnnotation + +776 +00:34:26,588 --> 00:34:29,507 +is in fact an Airport +and not something else + +777 +00:34:29,507 --> 00:34:31,845 +that we implement MKAnnotation on. + +778 +00:34:31,845 --> 00:34:32,901 +And if that's true, + +779 +00:34:32,901 --> 00:34:36,283 +then I can set my destination +to be this airport. + +780 +00:34:39,678 --> 00:34:42,686 +So in this way, we are +just creating a Binding + +781 +00:34:42,686 --> 00:34:47,227 +that binds to and from +our draft's destination. + +782 +00:34:47,227 --> 00:34:48,455 +And we pass that Binding + +783 +00:34:48,455 --> 00:34:52,256 +right off to our MapView right here. + +784 +00:34:52,256 --> 00:34:54,684 +So far our MapView is not doing anything + +785 +00:34:54,684 --> 00:34:55,827 +to set the selection. + +786 +00:34:55,827 --> 00:34:57,466 +It's still just looking at the selection. + +787 +00:34:57,466 --> 00:34:59,224 +But let's make sure we +haven't broken anything. + +788 +00:34:59,224 --> 00:35:01,540 +We shouldn't 'cause we're still Binding + +789 +00:35:01,540 --> 00:35:02,449 +to our draft destination. + +790 +00:35:02,449 --> 00:35:03,692 +So when we go over here, + +791 +00:35:03,692 --> 00:35:05,573 +see, it's still San Francisco. + +792 +00:35:05,573 --> 00:35:07,343 +If we change this to Boston, + +793 +00:35:07,343 --> 00:35:11,700 +the whole SwiftUI View updating happens + +794 +00:35:11,700 --> 00:35:12,941 +and we get to see Boston, + +795 +00:35:12,941 --> 00:35:13,951 +so that's working. + +796 +00:35:13,951 --> 00:35:16,308 +But we haven't done anything yet + +797 +00:35:16,308 --> 00:35:18,120 +on the other side of the Binding + +798 +00:35:18,120 --> 00:35:20,199 +so that when we pick an airport here, + +799 +00:35:20,199 --> 00:35:22,810 +it set the selection. + +800 +00:35:22,810 --> 00:35:25,877 +So we need to have our +MapView set the selection. + +801 +00:35:25,877 --> 00:35:29,810 +How do we know when a +pin has been touched on? + +802 +00:35:29,810 --> 00:35:33,096 +In MapView we do that with the delegate. + +803 +00:35:33,096 --> 00:35:35,161 +So there's another delegate method here, + +804 +00:35:35,161 --> 00:35:38,336 +mapView didSelect, where is that? + +805 +00:35:38,336 --> 00:35:40,979 +There it is, mapView didSelect. + +806 +00:35:40,979 --> 00:35:42,824 +This delegate method is called + +807 +00:35:42,824 --> 00:35:46,937 +whenever one of these +pin Views is touched on. + +808 +00:35:46,937 --> 00:35:48,985 +And this is the pin View that +was touched on right here, + +809 +00:35:48,985 --> 00:35:53,621 +MKAnnotationView, in this our +case it's a pin annotation. + +810 +00:35:53,621 --> 00:35:56,198 +So we can get the annotation +that was clicked on + +811 +00:35:56,198 --> 00:35:58,973 +by just asking the annotation View + +812 +00:35:58,973 --> 00:36:01,243 +what annotation do you have? + +813 +00:36:01,243 --> 00:36:04,637 +It's asking this pin thing +what's your annotation? + +814 +00:36:04,637 --> 00:36:06,226 +Now we have the annotation, + +815 +00:36:06,226 --> 00:36:08,989 +we kinda wanna do +something along the lines + +816 +00:36:08,989 --> 00:36:13,989 +of self.selection equals that annotation + +817 +00:36:14,719 --> 00:36:19,342 +except that self.selection is +not here in our Coordinator. + +818 +00:36:19,342 --> 00:36:22,706 +It's up here in our UIViewRepresentable. + +819 +00:36:22,706 --> 00:36:25,464 +This is nested class but +it can't see the vars + +820 +00:36:25,464 --> 00:36:27,657 +of this outer class right here. + +821 +00:36:27,657 --> 00:36:31,773 +So we have to bind this +selection from here + +822 +00:36:31,773 --> 00:36:34,799 +out to this Binding out here. + +823 +00:36:34,799 --> 00:36:38,326 +So let's just create +another Binding right here, + +824 +00:36:38,326 --> 00:36:40,913 +var selection, it's an MKAnnotation. + +825 +00:36:42,610 --> 00:36:44,453 +And then when we create our Coordinator, + +826 +00:36:44,453 --> 00:36:48,754 +let's pass the selection, $selection + +827 +00:36:48,754 --> 00:36:52,537 +which is the dollar sign +version of our Binding, + +828 +00:36:52,537 --> 00:36:55,768 +and we know that dollar of a +Binding is the Binding itself + +829 +00:36:55,768 --> 00:36:59,619 +or a Binding to the same thing +that the Binding binds to. + +830 +00:36:59,619 --> 00:37:00,980 +But this doesn't quite work + +831 +00:37:00,980 --> 00:37:03,561 +because this is a class, not a struct, + +832 +00:37:03,561 --> 00:37:06,313 +so we don't get this free constructor. + +833 +00:37:06,313 --> 00:37:09,074 +We have to create our own init selection + +834 +00:37:09,074 --> 00:37:13,677 +that takes a Binding to +an MKAnnotation Optional. + +835 +00:37:15,986 --> 00:37:20,212 +And then again we can't say +self.selection equals selection. + +836 +00:37:20,212 --> 00:37:22,052 +This is an @Binding, + +837 +00:37:22,052 --> 00:37:24,479 +so we have to say _selection. + +838 +00:37:24,479 --> 00:37:27,670 +The actual struct is the +thing that's passing here. + +839 +00:37:27,670 --> 00:37:30,196 +So now our selection binds both ways. + +840 +00:37:30,196 --> 00:37:33,639 +When the delegate notices +this one's been clicked on, + +841 +00:37:33,639 --> 00:37:36,129 +it sets it in the selection Binding here + +842 +00:37:36,129 --> 00:37:38,602 +which binds to this selection right here + +843 +00:37:38,602 --> 00:37:42,413 +which binds back out to +this Binding out here, + +844 +00:37:42,413 --> 00:37:45,610 +and that's going to set +our draft destination. + +845 +00:37:45,610 --> 00:37:48,027 +Let's see that in action. + +846 +00:37:50,080 --> 00:37:51,807 +Go to our filter. + +847 +00:37:51,807 --> 00:37:53,172 +Binding correctly this way, + +848 +00:37:53,172 --> 00:37:54,832 +we got San Francisco right here. + +849 +00:37:54,832 --> 00:37:57,067 +Let's go find a different airport. + +850 +00:37:57,067 --> 00:37:59,194 +How about Oakland right there? + +851 +00:37:59,194 --> 00:38:00,287 +Woo! + +852 +00:38:00,287 --> 00:38:01,250 +Look at that! + +853 +00:38:01,250 --> 00:38:04,058 +It zoomed in on it and +it picked it up here. + +854 +00:38:04,058 --> 00:38:05,680 +It can pick the other way. + +855 +00:38:05,680 --> 00:38:07,881 +Let's go Boston. + +856 +00:38:07,881 --> 00:38:09,271 +Here's Boston. + +857 +00:38:09,271 --> 00:38:11,199 +Zoom out again. + +858 +00:38:11,199 --> 00:38:12,906 +Over here to Newark. + +859 +00:38:12,906 --> 00:38:14,288 +Woo, it did it again. + +860 +00:38:14,288 --> 00:38:15,415 +And if we click Done, + +861 +00:38:15,415 --> 00:38:18,200 +it has picked this Newark. + +862 +00:38:18,200 --> 00:38:19,759 +We get to see Newark Airport. + +863 +00:38:19,759 --> 00:38:20,921 +So that is it. + +864 +00:38:20,921 --> 00:38:22,284 +It's all I wanted to show you + +865 +00:38:22,284 --> 00:38:25,631 +on this ViewRepresentable side. + +866 +00:38:25,631 --> 00:38:26,587 +The next demo we're gonna do + +867 +00:38:26,587 --> 00:38:28,686 +is ViewControllerRepresentable. + +868 +00:38:28,686 --> 00:38:32,131 +But this one really shows +you kind of all the things + +869 +00:38:32,131 --> 00:38:34,967 +you need to know about +Binding into a UIKit View + +870 +00:38:34,967 --> 00:38:38,431 +including, if you have to, +building your own custom Binding + +871 +00:38:38,431 --> 00:38:40,981 +with get and set to be +able to bind in there. + +872 +00:38:40,981 --> 00:38:43,176 +But all other times you won't +even need a custom Binding. + +873 +00:38:43,176 --> 00:38:45,665 +You'll have an ObservedObject +you can bind to + +874 +00:38:45,665 --> 00:38:48,740 +or you can bind directly +to a State or whatever + +875 +00:38:48,740 --> 00:38:52,204 +that you can then pass +into what's going on here. + +876 +00:38:52,204 --> 00:38:55,072 +And you might well have to pass +it to the delegate and back + +877 +00:38:55,072 --> 00:38:57,649 +like we have here 'cause the +delegate is usually the one + +878 +00:38:57,649 --> 00:39:01,619 +handling most of the activity +going on in the UIKit View. + +879 +00:39:01,619 --> 00:39:03,838 +Alright, so that is it for Enroute + +880 +00:39:03,838 --> 00:39:05,510 +and the ViewRepresentable. + +881 +00:39:05,510 --> 00:39:10,510 +Let's move over to our other +demo which is an EmojiArt demo. + +882 +00:39:12,655 --> 00:39:15,038 +So in this demo we're going to be wrapping + +883 +00:39:15,038 --> 00:39:16,283 +a whole bunch of Views, + +884 +00:39:16,283 --> 00:39:19,337 +a Controller that's +controlling all bunch of Views + +885 +00:39:19,337 --> 00:39:22,101 +that we're gonna present using a sheet, + +886 +00:39:22,101 --> 00:39:24,271 +and this sheet that we're gonna present + +887 +00:39:24,271 --> 00:39:25,618 +lets you take a picture from the camera + +888 +00:39:25,618 --> 00:39:27,011 +or the photo library. + +889 +00:39:27,011 --> 00:39:28,835 +We'll start with the photo library here + +890 +00:39:28,835 --> 00:39:31,600 +and use that as the background +image of our EmojiArt, + +891 +00:39:31,600 --> 00:39:33,445 +and then we'll move on to the camera + +892 +00:39:33,445 --> 00:39:34,759 +'cause there's a couple +of things to think about + +893 +00:39:34,759 --> 00:39:36,460 +with the camera that +are a little different. + +894 +00:39:36,460 --> 00:39:38,514 +So where are we gonna put the UI + +895 +00:39:38,514 --> 00:39:42,388 +that lets us take a picture +and put it as our background + +896 +00:39:42,388 --> 00:39:45,662 +and then drop it right up +in the navigationBarItems? + +897 +00:39:45,662 --> 00:39:47,447 +We already have one right there + +898 +00:39:47,447 --> 00:39:49,768 +for our pasteboard button on the right. + +899 +00:39:49,768 --> 00:39:53,045 +So let's put on the other +side, the leading side, + +900 +00:39:53,045 --> 00:39:56,437 +some buttons or something that +lets us choose this stuff. + +901 +00:39:56,437 --> 00:39:59,397 +We'll call this my pickImage. + +902 +00:40:00,394 --> 00:40:04,661 +And my pickImage is just going +to be a little var down here, + +903 +00:40:04,661 --> 00:40:07,740 +pickImage, some View. + +904 +00:40:07,740 --> 00:40:11,513 +We could even make this private of course + +905 +00:40:11,513 --> 00:40:12,346 +and just pickImage. + +906 +00:40:12,346 --> 00:40:16,165 +And let's us make it be +an Image, systemName. + +907 +00:40:16,165 --> 00:40:18,214 +How about the image "photo"? + +908 +00:40:18,214 --> 00:40:22,786 +That's a good system image I +think for picking a photo here. + +909 +00:40:22,786 --> 00:40:24,423 +And I'm gonna make this larger. + +910 +00:40:24,423 --> 00:40:25,382 +I'm not really sure + +911 +00:40:25,382 --> 00:40:27,685 +whether we should be +making that larger there + +912 +00:40:27,685 --> 00:40:28,754 +but it's good for demos, + +913 +00:40:28,754 --> 00:40:30,710 +easy to see what's going on up there. + +914 +00:40:30,710 --> 00:40:33,663 +And I'm also gonna set the +color to be the .accentColor, + +915 +00:40:33,663 --> 00:40:35,216 +the same thing a Button would use. + +916 +00:40:35,216 --> 00:40:37,194 +And in fact I could use a Button here, + +917 +00:40:37,194 --> 00:40:41,275 +but just for variety, +let's do an onTapGesture. + +918 +00:40:41,275 --> 00:40:44,125 +This Image is going to appear in our UI. + +919 +00:40:44,125 --> 00:40:45,543 +Let's take a look at it. + +920 +00:40:49,552 --> 00:40:50,730 +There it is right there. + +921 +00:40:50,730 --> 00:40:52,453 +And when I click on this, + +922 +00:40:52,453 --> 00:40:56,515 +I want it to bring up this UIKit UI + +923 +00:40:56,515 --> 00:40:59,826 +that lets us choose from the +photo library in this case. + +924 +00:40:59,826 --> 00:41:02,895 +And later we'll add another +button for the camera. + +925 +00:41:02,895 --> 00:41:06,409 +So how do I make a sheet appear? + +926 +00:41:06,409 --> 00:41:08,408 +We know exactly how to do that, right? + +927 +00:41:08,408 --> 00:41:12,077 +We just set some sort of boolean variable. + +928 +00:41:12,077 --> 00:41:14,189 +I'm gonna call my boolean variable + +929 +00:41:14,189 --> 00:41:17,724 +showImagePicker = true. + +930 +00:41:17,724 --> 00:41:21,406 +I need a little private @State for that. + +931 +00:41:21,406 --> 00:41:23,620 +We'll start out as false of course. + +932 +00:41:23,620 --> 00:41:27,693 +And then we're just going +to .sheet isPresented, + +933 +00:41:28,600 --> 00:41:32,232 +put a Binding to that showImagePicker, + +934 +00:41:32,232 --> 00:41:35,213 +and then we're going to have to provide + +935 +00:41:35,213 --> 00:41:38,726 +whatever sheet it is that we present. + +936 +00:41:38,726 --> 00:41:42,688 +In this case it's gonna be ImagePicker. + +937 +00:41:42,688 --> 00:41:46,115 +This is gonna be a +UIViewControllerRepresentable + +938 +00:41:46,115 --> 00:41:49,495 +that puts up the photo picker. + +939 +00:41:49,495 --> 00:41:52,433 +Let's go ahead and do this, File, New. + +940 +00:41:52,433 --> 00:41:54,225 +Again it is a SwiftUI View, + +941 +00:41:54,225 --> 00:41:55,983 +but since it's a Representable, + +942 +00:41:55,983 --> 00:41:58,070 +we don't need the var body and all that. + +943 +00:41:58,070 --> 00:42:00,383 +We'll call it my ImagePicker. + +944 +00:42:03,540 --> 00:42:04,373 +And here it is. + +945 +00:42:04,373 --> 00:42:06,172 +As usual we're doing the integration, + +946 +00:42:06,172 --> 00:42:08,423 +we need both SwiftUI and UIKit. + +947 +00:42:10,432 --> 00:42:13,180 +And this is just a +struct called ImagePicker + +948 +00:42:13,180 --> 00:42:15,230 +which is a UIViewControllerRepresentable. + +949 +00:42:19,921 --> 00:42:22,601 +And it has exactly the same functions + +950 +00:42:22,601 --> 00:42:23,590 +as we had in the other ones, + +951 +00:42:23,590 --> 00:42:25,041 +so let's just type them right in + +952 +00:42:25,041 --> 00:42:26,656 +since we already know how to do this. + +953 +00:42:26,656 --> 00:42:31,656 +There's the makeUIViewController +that has the context. + +954 +00:42:31,840 --> 00:42:33,688 +Now the kind of ViewController + +955 +00:42:33,688 --> 00:42:35,462 +that we're going to make here + +956 +00:42:35,462 --> 00:42:37,293 +is called a UIImagePickerController. + +957 +00:42:39,473 --> 00:42:40,650 +This is just a MVC, a Controller in UIKit + +958 +00:42:43,885 --> 00:42:45,952 +that we can use to choose a photo + +959 +00:42:45,952 --> 00:42:48,632 +from our photo library or our camera. + +960 +00:42:48,632 --> 00:42:51,567 +Let's let picker equal +one of these things. + +961 +00:42:51,567 --> 00:42:53,133 +I'm gonna create one. + +962 +00:42:54,114 --> 00:42:55,693 +And return it. + +963 +00:42:56,577 --> 00:42:58,432 +And we're gonna have to configure it + +964 +00:42:58,432 --> 00:43:00,190 +a little bit inside here. + +965 +00:43:00,190 --> 00:43:02,136 +So we'll leave space for that. + +966 +00:43:02,136 --> 00:43:05,850 +Then of course we have our +updateUIViewController. + +967 +00:43:05,850 --> 00:43:07,825 +This takes an ImagePickerController. + +968 +00:43:07,825 --> 00:43:09,210 +Here's where we would update things. + +969 +00:43:09,210 --> 00:43:11,958 +I don't actually think we +have any updating to do + +970 +00:43:11,958 --> 00:43:14,362 +because we just present +this ViewController + +971 +00:43:14,362 --> 00:43:16,526 +and we're gonna have a delegate for it + +972 +00:43:16,526 --> 00:43:19,256 +but otherwise it's gonna do its thing. + +973 +00:43:19,256 --> 00:43:22,047 +We of course need makeCoordinator. + +974 +00:43:23,362 --> 00:43:25,033 +And we'll do the exact same thing, + +975 +00:43:25,033 --> 00:43:27,905 +we'll call it Coordinator, + +976 +00:43:27,905 --> 00:43:32,905 +and we'll have it be a +nested class Coordinator. + +977 +00:43:33,350 --> 00:43:35,447 +It has be an NSObject +because it's gonna be + +978 +00:43:35,447 --> 00:43:39,713 +the UIImagePickerController's delegate. + +979 +00:43:39,713 --> 00:43:41,507 +And just for good measure, + +980 +00:43:41,507 --> 00:43:42,957 +and I'm not gonna explain why + +981 +00:43:42,957 --> 00:43:44,784 +because we're not really that much + +982 +00:43:44,784 --> 00:43:46,763 +learning about UIImagePickerController + +983 +00:43:46,763 --> 00:43:49,443 +although we are gonna +learn a lot by doing this, + +984 +00:43:49,443 --> 00:43:52,395 +it also has to implement +another protocol here + +985 +00:43:52,395 --> 00:43:54,295 +called UINavigationControllerDelegate. + +986 +00:43:56,986 --> 00:44:00,894 +This is just a protocol +that this ImagePicker + +987 +00:44:00,894 --> 00:44:03,001 +requires its delegate to implement. + +988 +00:44:03,001 --> 00:44:04,964 +We're not gonna use any methods from it + +989 +00:44:04,964 --> 00:44:07,216 +but we still have to put it on there. + +990 +00:44:07,216 --> 00:44:08,974 +There are a couple methods in here, + +991 +00:44:08,974 --> 00:44:10,766 +and we really need them both. + +992 +00:44:10,766 --> 00:44:14,965 +One is the imagePickerController didCancel + +993 +00:44:14,965 --> 00:44:17,098 +and the other is the imagePickerController + +994 +00:44:17,098 --> 00:44:20,627 +didFinishPickingMedia. + +995 +00:44:20,627 --> 00:44:22,763 +So let's put them both in here. + +996 +00:44:24,164 --> 00:44:26,588 +This cancel one right here is called + +997 +00:44:26,588 --> 00:44:29,263 +when the person cancels +of course the Controller. + +998 +00:44:29,263 --> 00:44:32,057 +Remember we're putting up an +entire sheet worth of UI here + +999 +00:44:32,057 --> 00:44:33,977 +and it's gonna have a +"Cancel" button on it. + +1000 +00:44:33,977 --> 00:44:36,844 +And then this is the one where +we actually pick an image + +1001 +00:44:36,844 --> 00:44:39,694 +either from the camera or +from the photo library. + +1002 +00:44:39,694 --> 00:44:40,872 +So here's where the action + +1003 +00:44:40,872 --> 00:44:42,743 +is really happening in our delegate, + +1004 +00:44:42,743 --> 00:44:45,269 +and this is our PickerControllerDelegate, + +1005 +00:44:45,269 --> 00:44:48,470 +so let's set our picker's delegate + +1006 +00:44:48,470 --> 00:44:52,202 +to be our context.coordinator, right? + +1007 +00:44:52,202 --> 00:44:55,626 +We're setting this instance of +this that we're gonna create. + +1008 +00:44:55,626 --> 00:44:57,589 +And we'll create that here, Coordinator. + +1009 +00:44:57,589 --> 00:45:01,156 +It doesn't take any +arguments as yet anyway. + +1010 +00:45:01,156 --> 00:45:02,640 +Now we got it all set up. + +1011 +00:45:02,640 --> 00:45:04,955 +This is just exactly like +we set up the MapView. + +1012 +00:45:04,955 --> 00:45:06,969 +We got the delegate and all that. + +1013 +00:45:06,969 --> 00:45:09,715 +But one other thing we wanna +do in configuration here, + +1014 +00:45:09,715 --> 00:45:13,104 +to start is I'm gonna set +the picker's source type + +1015 +00:45:13,104 --> 00:45:14,946 +to be photo library. + +1016 +00:45:14,946 --> 00:45:17,588 +So the picker is going +to try and pick an image + +1017 +00:45:17,588 --> 00:45:19,467 +from the photo library to start. + +1018 +00:45:19,467 --> 00:45:21,121 +Eventually again we'll do the camera + +1019 +00:45:21,121 --> 00:45:24,350 +but for now just the photo library. + +1020 +00:45:24,350 --> 00:45:26,831 +Alright, we go back to +our DocumentView up here. + +1021 +00:45:26,831 --> 00:45:29,254 +We've got our ImagePicker. + +1022 +00:45:29,254 --> 00:45:31,520 +It should compile now. + +1023 +00:45:31,520 --> 00:45:36,026 +Let's run, to our "House". + +1024 +00:45:36,026 --> 00:45:38,749 +Now when we tap on this, an onTapGesture, + +1025 +00:45:38,749 --> 00:45:40,248 +hopefully it will put up + +1026 +00:45:40,248 --> 00:45:43,623 +our nice photo library user interface. + +1027 +00:45:44,824 --> 00:45:46,136 +And there it is. + +1028 +00:45:46,136 --> 00:45:47,179 +Woo-hoo! + +1029 +00:45:47,179 --> 00:45:48,674 +Okay, there's our photos. + +1030 +00:45:48,674 --> 00:45:53,157 +Now if I pick one like this +thing here, nothing happens, + +1031 +00:45:53,157 --> 00:45:55,520 +but if I hit "Cancel", nothing happens. + +1032 +00:45:55,520 --> 00:46:00,060 +That's because back here +in our pickImage over here, + +1033 +00:46:00,060 --> 00:46:02,604 +we put this sheet up, the ImagePicker up, + +1034 +00:46:02,604 --> 00:46:06,018 +but we don't do anything when +it gets canceled or picked, + +1035 +00:46:06,018 --> 00:46:09,585 +so of course this thing +never gets put away, + +1036 +00:46:09,585 --> 00:46:11,783 +this showImagePicker +never gets set to false, + +1037 +00:46:11,783 --> 00:46:14,422 +and clearly we're not grabbing the image. + +1038 +00:46:14,422 --> 00:46:16,167 +But we've got this thing presenting, + +1039 +00:46:16,167 --> 00:46:18,842 +so now let's just do +the little bit of work + +1040 +00:46:18,842 --> 00:46:21,127 +to get this Image out of here. + +1041 +00:46:21,127 --> 00:46:24,069 +Now how am I gonna get +that Image out of here? + +1042 +00:46:24,069 --> 00:46:26,922 +One way to do it will be the +same way we did the MapView, + +1043 +00:46:26,922 --> 00:46:30,952 +put an @Binding here and bind to the Image + +1044 +00:46:30,952 --> 00:46:33,036 +and then the Image will be chosen + +1045 +00:46:33,036 --> 00:46:36,296 +and we would have to pass it +down here to the delegate, + +1046 +00:46:36,296 --> 00:46:38,088 +and it could set the Binding here + +1047 +00:46:38,088 --> 00:46:39,549 +and it would transport back. + +1048 +00:46:39,549 --> 00:46:41,017 +That is one way to do it. + +1049 +00:46:41,017 --> 00:46:43,799 +Just to show you there are +other ways to do things, + +1050 +00:46:43,799 --> 00:46:46,137 +I'm gonna do this a little differently. + +1051 +00:46:46,137 --> 00:46:51,137 +I'm going to add a var +here to my Representable + +1052 +00:46:51,954 --> 00:46:53,893 +which is called handlePickedImage, + +1053 +00:46:56,475 --> 00:47:00,874 +and it's going to be closure, +UIImage, return void. + +1054 +00:47:00,874 --> 00:47:05,416 +And I'm going to call this +closure when you pick your Image. + +1055 +00:47:05,416 --> 00:47:08,410 +Now I'm gonna give you nil if you canceled + +1056 +00:47:08,410 --> 00:47:10,243 +or for some reason I +couldn't get the Image. + +1057 +00:47:10,243 --> 00:47:14,189 +And I'm gonna give you an Image +if you actually picked it. + +1058 +00:47:14,189 --> 00:47:16,510 +Now we know that this handlePickedImage + +1059 +00:47:16,510 --> 00:47:18,383 +is actually happening down here. + +1060 +00:47:18,383 --> 00:47:20,469 +So we have to do the same +thing we did with our map, + +1061 +00:47:20,469 --> 00:47:22,309 +and this is very common to have to do, + +1062 +00:47:22,309 --> 00:47:24,811 +we're gonna have to do the same function + +1063 +00:47:24,811 --> 00:47:27,456 +down here in our Coordinator, + +1064 +00:47:27,456 --> 00:47:32,456 +var handlePickedImage UIImage, and Void, + +1065 +00:47:34,964 --> 00:47:37,337 +and pass that to our Coordinator, + +1066 +00:47:37,337 --> 00:47:42,299 +handlePickedImage, call +in handlePickedImage. + +1067 +00:47:42,299 --> 00:47:43,941 +And again this is a class + +1068 +00:47:43,941 --> 00:47:46,137 +so we don't get this free +constructor right here, + +1069 +00:47:46,137 --> 00:47:50,284 +so we have to say init handlePickedImage + +1070 +00:47:50,284 --> 00:47:55,284 +with this UIImage that returns a Void, + +1071 +00:47:55,557 --> 00:48:00,472 +self.handlePickedImage +equals handlePickedImage. + +1072 +00:48:00,472 --> 00:48:03,227 +I'm really getting used to +typing handlePickedImage. + +1073 +00:48:03,227 --> 00:48:06,303 +Of course we are grabbing on +to this and holding on to it + +1074 +00:48:06,303 --> 00:48:09,972 +so this is going to +have to be an @escaping. + +1075 +00:48:09,972 --> 00:48:12,893 +We know that anytime we have +a function that we pass in, + +1076 +00:48:12,893 --> 00:48:14,990 +when we hold on to it, we +have to let people know + +1077 +00:48:14,990 --> 00:48:16,260 +that that's what we're doing + +1078 +00:48:16,260 --> 00:48:18,010 +that we're grabbing on to it there. + +1079 +00:48:18,881 --> 00:48:21,403 +Now that we have this +handlePickedImage here, + +1080 +00:48:21,403 --> 00:48:23,232 +let's just, when we cancel, + +1081 +00:48:23,232 --> 00:48:26,902 +call our handlePickedImage(nil) + +1082 +00:48:26,902 --> 00:48:28,131 +so we know that you canceled. + +1083 +00:48:28,131 --> 00:48:32,415 +And here I'm gonna do my +handlePickedImage with the image. + +1084 +00:48:32,415 --> 00:48:34,241 +Now how do I get the image? + +1085 +00:48:34,241 --> 00:48:36,897 +When imagePickerControllerDelegate +gets called, + +1086 +00:48:36,897 --> 00:48:39,747 +this didFinishPickingMediaWithInfo, + +1087 +00:48:39,747 --> 00:48:41,386 +we get this Dictionary, + +1088 +00:48:41,386 --> 00:48:45,004 +and this Dictionary has info +like how big the image was + +1089 +00:48:45,004 --> 00:48:47,222 +and what the actual image was. + +1090 +00:48:47,222 --> 00:48:49,179 +And this Dictionary has a bunch of keys. + +1091 +00:48:49,179 --> 00:48:52,814 +One of the info's keys is .originalImage, + +1092 +00:48:52,814 --> 00:48:55,732 +and that gives us the +original image as a UIImage. + +1093 +00:48:55,732 --> 00:48:58,838 +Of course this Dictionary +has Any's as the values. + +1094 +00:48:58,838 --> 00:49:01,942 +This is an old Objective-C API here. + +1095 +00:49:01,942 --> 00:49:06,096 +So we need to say as? UIImage +and see if we can cast it. + +1096 +00:49:06,096 --> 00:49:07,608 +And we're doing as?. + +1097 +00:49:07,608 --> 00:49:10,199 +This will return nil if for some reason + +1098 +00:49:10,199 --> 00:49:12,182 +this is not a UIImage, + +1099 +00:49:12,182 --> 00:49:14,845 +and that's okay 'cause the +handlePickedImage will have nil + +1100 +00:49:14,845 --> 00:49:16,870 +and that'll be just like canceling, + +1101 +00:49:16,870 --> 00:49:18,988 +no different from canceling. + +1102 +00:49:18,988 --> 00:49:21,123 +Now one thing I'm gonna +do while we're here, + +1103 +00:49:21,123 --> 00:49:23,252 +I don't think we did this all quarter, + +1104 +00:49:23,252 --> 00:49:25,441 +which is typealiasing. + +1105 +00:49:25,441 --> 00:49:29,633 +I had to type this type +all bunch of times in here. + +1106 +00:49:29,633 --> 00:49:32,125 +And when you have kind of a complex type + +1107 +00:49:32,125 --> 00:49:35,870 +like that's not a String +or some name of a struct, + +1108 +00:49:35,870 --> 00:49:38,636 +a lot of times we'll create a typealias. + +1109 +00:49:38,636 --> 00:49:43,397 +For example I might call this +thing my PickedImageHandler + +1110 +00:49:43,397 --> 00:49:47,832 +and it equals UIImage returning Void. + +1111 +00:49:47,832 --> 00:49:51,094 +And then everywhere where I use this, + +1112 +00:49:51,094 --> 00:49:53,583 +I'm going to put this instead. + +1113 +00:49:53,583 --> 00:49:56,380 +So here, and here, and here. + +1114 +00:49:56,380 --> 00:49:57,543 +I couldn't put that. + +1115 +00:49:57,543 --> 00:49:59,223 +It's kind of good for my API. + +1116 +00:49:59,223 --> 00:50:02,714 +It's a little more descriptive +of what this function was, + +1117 +00:50:02,714 --> 00:50:04,166 +and it also cleans up things, + +1118 +00:50:04,166 --> 00:50:06,214 +and I don't have to worry about +typing this over and over, + +1119 +00:50:06,214 --> 00:50:07,818 +and I might make a mistake + +1120 +00:50:07,818 --> 00:50:09,770 +when I'm doing it typing it over and over, + +1121 +00:50:09,770 --> 00:50:11,606 +so like I might forget my question mark + +1122 +00:50:11,606 --> 00:50:12,596 +or something like that, + +1123 +00:50:12,596 --> 00:50:14,796 +this prevents that as well. + +1124 +00:50:14,796 --> 00:50:17,187 +It's quite common to make typealiases + +1125 +00:50:17,187 --> 00:50:18,553 +for functions arguments + +1126 +00:50:18,553 --> 00:50:21,833 +especially if they're pass +around a lot of places. + +1127 +00:50:22,922 --> 00:50:25,925 +All we have to do now is +set this handlePickedImage + +1128 +00:50:25,925 --> 00:50:28,042 +when we do our ImagePicker over here. + +1129 +00:50:28,042 --> 00:50:29,360 +So here's our ImagePicker. + +1130 +00:50:29,360 --> 00:50:30,589 +Let's do it. + +1131 +00:50:30,589 --> 00:50:34,018 +The image given back to us here. + +1132 +00:50:34,018 --> 00:50:36,254 +Now we know that we have to check to see + +1133 +00:50:36,254 --> 00:50:38,097 +if the image does not equal nil, + +1134 +00:50:38,097 --> 00:50:39,354 +and if it does not equal nil, + +1135 +00:50:39,354 --> 00:50:42,033 +then we've got to actually +use it as our background. + +1136 +00:50:42,033 --> 00:50:43,311 +And in any case though + +1137 +00:50:43,311 --> 00:50:45,888 +we're going to set our +showImagePicker to false. + +1138 +00:50:45,888 --> 00:50:50,291 +We want to dismiss this +sheet that we presented. + +1139 +00:50:50,291 --> 00:50:52,732 +Now what are we gonna do +if the image is not nil? + +1140 +00:50:52,732 --> 00:50:55,650 +This is where we're gonna +do that kind of bogus thing + +1141 +00:50:55,650 --> 00:50:57,186 +that I was talking about there + +1142 +00:50:57,186 --> 00:51:00,415 +where we're gonna throw this +thing into the file system, + +1143 +00:51:00,415 --> 00:51:03,580 +this image into the file +system and grab a URL to it + +1144 +00:51:03,580 --> 00:51:05,093 +and set that as our background URL. + +1145 +00:51:05,093 --> 00:51:08,402 +Again that would tie this whole thing, + +1146 +00:51:08,402 --> 00:51:11,306 +this document that we're +creating to this device + +1147 +00:51:11,306 --> 00:51:13,831 +'cause we're pointing +into its own sandbox. + +1148 +00:51:13,831 --> 00:51:17,228 +Also by the way I had to go +back in my EmojiArt's extension + +1149 +00:51:17,228 --> 00:51:19,771 +and play a little bit with this image URL. + +1150 +00:51:19,771 --> 00:51:21,665 +I had to actually check for file URLs + +1151 +00:51:21,665 --> 00:51:25,407 +because one thing to +note is that as you're, + +1152 +00:51:25,407 --> 00:51:27,557 +especially doing your development + +1153 +00:51:27,557 --> 00:51:29,418 +and running new versions of your app, + +1154 +00:51:29,418 --> 00:51:31,412 +the Application Support directory + +1155 +00:51:31,412 --> 00:51:34,619 +which is where I decided to +put this thing, this image, + +1156 +00:51:34,619 --> 00:51:38,457 +it changes the URL, it +changes from launch to launch. + +1157 +00:51:38,457 --> 00:51:40,419 +So here I just have a thing where + +1158 +00:51:40,419 --> 00:51:43,679 +whenever I see a file URL +as our background image, + +1159 +00:51:43,679 --> 00:51:47,092 +I'm going in re-looking it +up in Application Support + +1160 +00:51:47,092 --> 00:51:48,349 +to get the new version. + +1161 +00:51:48,349 --> 00:51:49,981 +So that's a little bit annoying. + +1162 +00:51:49,981 --> 00:51:52,131 +I think I also had to +go over in our Document + +1163 +00:51:52,131 --> 00:51:54,176 +and make sure that whenever I fetch + +1164 +00:51:54,176 --> 00:51:55,450 +the background image data, + +1165 +00:51:55,450 --> 00:51:57,498 +I call that imageURL again. + +1166 +00:51:57,498 --> 00:51:59,853 +I was originally only +calling when we set it, + +1167 +00:51:59,853 --> 00:52:01,355 +but now I'm calling it every time + +1168 +00:52:01,355 --> 00:52:04,321 +to make sure this file +URL gets properly set. + +1169 +00:52:04,321 --> 00:52:07,465 +So that's just a lot of +kind of fratzing around + +1170 +00:52:07,465 --> 00:52:09,919 +to make this demo go really smooth + +1171 +00:52:09,919 --> 00:52:12,858 +because I can now type this +one line of code right here + +1172 +00:52:12,858 --> 00:52:17,685 +which is self.document.backgroundURL + +1173 +00:52:17,685 --> 00:52:22,603 +equals that image storeInFilesystem, + +1174 +00:52:22,603 --> 00:52:24,480 +and store in the file system, + +1175 +00:52:24,480 --> 00:52:27,537 +just this little extension +down here that I wrote. + +1176 +00:52:27,537 --> 00:52:30,174 +And you know how to do all this +now after the last lecture, + +1177 +00:52:30,174 --> 00:52:33,093 +getting the directory, +appendingPathComponent. + +1178 +00:52:33,093 --> 00:52:37,016 +I use this jpegData function +on UIImage to get the data + +1179 +00:52:37,016 --> 00:52:41,017 +and then I write to that URL, +put it into the filesystem, + +1180 +00:52:41,017 --> 00:52:44,578 +and I return the URL that I wrote it to. + +1181 +00:52:44,578 --> 00:52:47,514 +Really simple, makes this +a one-liner right here. + +1182 +00:52:47,514 --> 00:52:49,528 +One other thing I'm gonna do here + +1183 +00:52:49,528 --> 00:52:52,446 +which we haven't talked about this either, + +1184 +00:52:52,446 --> 00:52:56,013 +I'm little worried that this closure + +1185 +00:52:56,013 --> 00:52:58,521 +might be called at an inopportune time. + +1186 +00:52:58,521 --> 00:53:00,552 +For example, I'm not really allowed + +1187 +00:53:00,552 --> 00:53:04,325 +to modify myself as a View + +1188 +00:53:04,325 --> 00:53:08,240 +while I'm in the middle +of processing events. + +1189 +00:53:08,240 --> 00:53:10,955 +You kinda have to wait for +everything to settle back down. + +1190 +00:53:10,955 --> 00:53:13,600 +So to be safe, this closure right here, + +1191 +00:53:13,600 --> 00:53:15,665 +I'm not gonna do this backgroundURL + +1192 +00:53:15,665 --> 00:53:17,918 +which I know is gonna update my UI. + +1193 +00:53:17,918 --> 00:53:22,918 +I'm going to do it in a +DispatchQueue.main.async. + +1194 +00:53:23,842 --> 00:53:25,139 +Now why would I be doing this? + +1195 +00:53:25,139 --> 00:53:28,210 +There's no issue here +with multi-threading. + +1196 +00:53:28,210 --> 00:53:30,345 +None of this is happening +on a background thread. + +1197 +00:53:30,345 --> 00:53:33,261 +This has nothing to do +actually with multi-threading. + +1198 +00:53:33,261 --> 00:53:37,274 +It's just that if I ask my main +queue to go do this closure, + +1199 +00:53:37,274 --> 00:53:38,656 +it's gonna put it on its list, + +1200 +00:53:38,656 --> 00:53:41,130 +and even though I'm running +in the main queue right here, + +1201 +00:53:41,130 --> 00:53:43,070 +it's gonna finish doing all +the things it's doing here, + +1202 +00:53:43,070 --> 00:53:44,504 +maybe updating my Views, + +1203 +00:53:44,504 --> 00:53:45,477 +and when it's done, + +1204 +00:53:45,477 --> 00:53:48,549 +it's gonna go to its queue +and grab the next one + +1205 +00:53:48,549 --> 00:53:51,051 +which hopefully will +be mine and execute it. + +1206 +00:53:51,051 --> 00:53:53,560 +So it's essentially just saying do this + +1207 +00:53:53,560 --> 00:53:55,331 +after everything settles down. + +1208 +00:53:55,331 --> 00:53:58,345 +And if you start getting +warnings when you run, + +1209 +00:53:58,345 --> 00:54:00,393 +that say, oh, you can't update, + +1210 +00:54:00,393 --> 00:54:02,810 +you're not allowed to modify the View + +1211 +00:54:02,810 --> 00:54:03,643 +while it's in the middle + +1212 +00:54:03,643 --> 00:54:06,217 +of constructing its body or whatever, + +1213 +00:54:06,217 --> 00:54:09,184 +then you might think of +delaying something like this. + +1214 +00:54:09,184 --> 00:54:12,771 +And we might have wanted to +do that in Enroute as well. + +1215 +00:54:12,771 --> 00:54:17,771 +Okay, in Enroute when you +click the Airports in the map, + +1216 +00:54:18,458 --> 00:54:21,616 +maybe that selection of the Airports + +1217 +00:54:21,616 --> 00:54:24,841 +should have been done this +way too just to be safe. + +1218 +00:54:24,841 --> 00:54:26,234 +I didn't see it have any problems + +1219 +00:54:26,234 --> 00:54:29,546 +but anytime you're having +callbacks right here + +1220 +00:54:29,546 --> 00:54:31,765 +that are happening especially from UIKit + +1221 +00:54:31,765 --> 00:54:35,801 +'cause UIKit's in a little +different world than SwiftUI, + +1222 +00:54:35,801 --> 00:54:38,655 +that's sometimes a little +safety buffer you can put in it. + +1223 +00:54:38,655 --> 00:54:39,741 +Not gonna hurt anything. + +1224 +00:54:39,741 --> 00:54:42,677 +We're just essentially doing +a user Intent here, right? + +1225 +00:54:42,677 --> 00:54:46,681 +This is an Intent, an Intent +to change the background URL. + +1226 +00:54:46,681 --> 00:54:50,111 +Perfectly fine to delay +that a short moment + +1227 +00:54:50,111 --> 00:54:52,227 +as we wait for the dispatch +queue to settle down + +1228 +00:54:52,227 --> 00:54:53,470 +and come back around. + +1229 +00:54:53,470 --> 00:54:55,623 +Let's see if this works. + +1230 +00:54:58,133 --> 00:54:58,966 +Right, here's our "House". + +1231 +00:54:58,966 --> 00:55:01,526 +Let's see if we can change +the background from the house + +1232 +00:55:01,526 --> 00:55:04,217 +to be something from our photo library. + +1233 +00:55:04,217 --> 00:55:06,423 +Let's click on the photo library. + +1234 +00:55:07,425 --> 00:55:08,893 +Here it is. + +1235 +00:55:08,893 --> 00:55:12,370 +Let's go pick this nice little green. + +1236 +00:55:12,370 --> 00:55:14,607 +Woo-hoo it works! + +1237 +00:55:14,607 --> 00:55:16,430 +And we can zoom in and out and everything. + +1238 +00:55:16,430 --> 00:55:18,937 +And we could even make sure + +1239 +00:55:18,937 --> 00:55:21,040 +that it's really saving things here. + +1240 +00:55:21,040 --> 00:55:26,040 +Let's go back, run again, "House". + +1241 +00:55:26,480 --> 00:55:28,328 +Woo-hoo, it's still in there! + +1242 +00:55:28,328 --> 00:55:29,658 +I'm zoomed in. + +1243 +00:55:29,658 --> 00:55:30,833 +Alright. + +1244 +00:55:30,833 --> 00:55:31,800 +So this is great. + +1245 +00:55:31,800 --> 00:55:34,236 +This is working for the photo library. + +1246 +00:55:34,236 --> 00:55:36,590 +Very simple, very powerful. + +1247 +00:55:36,590 --> 00:55:38,608 +It looks really nice in our code. + +1248 +00:55:38,608 --> 00:55:41,954 +Here our SwiftUI code is all SwiftUI-ish. + +1249 +00:55:41,954 --> 00:55:45,146 +There's really not a +lot of weird stuff here. + +1250 +00:55:45,146 --> 00:55:47,764 +And even the ImagePicker, +pretty straightforward. + +1251 +00:55:47,764 --> 00:55:49,901 +This is pretty much a +minimal amount of code + +1252 +00:55:49,901 --> 00:55:53,280 +to get a UIImagePicker working. + +1253 +00:55:53,280 --> 00:55:54,953 +Now what about the camera? + +1254 +00:55:54,953 --> 00:55:58,690 +Making this UIImagePickerController +pick for the camera + +1255 +00:55:58,690 --> 00:55:59,646 +is really simple. + +1256 +00:55:59,646 --> 00:56:00,941 +It's actually just changing + +1257 +00:56:00,941 --> 00:56:05,002 +this photo library right +here to be .camera. + +1258 +00:56:05,002 --> 00:56:08,094 +However, I really wanna use all this code + +1259 +00:56:08,094 --> 00:56:10,528 +for both the photo library and the camera. + +1260 +00:56:10,528 --> 00:56:12,986 +So let's make this be a var here. + +1261 +00:56:12,986 --> 00:56:14,539 +So we'll say sourceType. + +1262 +00:56:14,539 --> 00:56:17,206 +We'll make this into a var here. + +1263 +00:56:18,959 --> 00:56:20,768 +And this type of this enum + +1264 +00:56:20,768 --> 00:56:23,413 +is UIImagePickerController.SourceType. + +1265 +00:56:26,784 --> 00:56:29,244 +That's the type of this enum essentially. + +1266 +00:56:29,244 --> 00:56:30,746 +And we just instantly made it + +1267 +00:56:30,746 --> 00:56:32,403 +so that this ImagePicker can either pick + +1268 +00:56:32,403 --> 00:56:35,400 +from the camera or from the photo library. + +1269 +00:56:35,400 --> 00:56:38,063 +And back here of course +now we have an error. + +1270 +00:56:38,063 --> 00:56:40,350 +We need to provide the sourceType. + +1271 +00:56:40,350 --> 00:56:45,350 +Let's create a little +imagePickerSourceType @State. + +1272 +00:56:52,100 --> 00:56:53,107 +And we'll set it equal to + +1273 +00:56:53,107 --> 00:56:58,107 +UIImagePickerController.SourceType.photoLibrary. + +1274 +00:56:58,415 --> 00:57:00,207 +It doesn't matter what we choose here + +1275 +00:57:00,207 --> 00:57:03,326 +because what we're gonna do is +we're gonna have this photo, + +1276 +00:57:03,326 --> 00:57:07,085 +one, set this self.imagePickerSourceType + +1277 +00:57:07,085 --> 00:57:09,337 +equal to the photoLibrary, + +1278 +00:57:09,337 --> 00:57:11,787 +and then we're gonna +have a whole other button + +1279 +00:57:11,787 --> 00:57:15,227 +right next to it, camera, + +1280 +00:57:15,227 --> 00:57:19,351 +and it's gonna have its +SourceType be the camera. + +1281 +00:57:19,351 --> 00:57:21,426 +I'll put these two things in an HStack + +1282 +00:57:21,426 --> 00:57:22,962 +so they'll be sitting side by side + +1283 +00:57:22,962 --> 00:57:26,053 +in that upper left corner, up there. + +1284 +00:57:26,938 --> 00:57:29,465 +And that's all we should +have to do, right? + +1285 +00:57:29,465 --> 00:57:30,723 +Let's take a look. + +1286 +00:57:34,305 --> 00:57:35,476 +Alright, here's our "House". + +1287 +00:57:35,476 --> 00:57:36,374 +We got them there. + +1288 +00:57:36,374 --> 00:57:38,353 +So let's see is there a photo library, + +1289 +00:57:38,353 --> 00:57:39,186 +it still seems to be working. + +1290 +00:57:39,186 --> 00:57:41,887 +We can choose different images. + +1291 +00:57:41,887 --> 00:57:42,808 +Works great. + +1292 +00:57:42,808 --> 00:57:45,242 +How about the camera? + +1293 +00:57:45,242 --> 00:57:47,010 +Whoa! + +1294 +00:57:47,010 --> 00:57:47,898 +Our app crashed. + +1295 +00:57:47,898 --> 00:57:49,330 +What is going on here? + +1296 +00:57:49,330 --> 00:57:50,840 +Let's look in the console. + +1297 +00:57:50,840 --> 00:57:52,676 +Of course every time you have crashes, + +1298 +00:57:52,676 --> 00:57:55,500 +you wanna go look in the +console see what happened. + +1299 +00:57:55,500 --> 00:57:59,205 +And sure enough here it is, +"Source type 1 not available." + +1300 +00:57:59,205 --> 00:58:01,227 +Oh yeah. + +1301 +00:58:01,227 --> 00:58:03,837 +And the simulator doesn't have a camera + +1302 +00:58:03,837 --> 00:58:05,891 +and so it crashes our app. + +1303 +00:58:05,891 --> 00:58:08,710 +So the camera UIImagePickerController, + +1304 +00:58:08,710 --> 00:58:10,140 +if you look at this documentation, + +1305 +00:58:10,140 --> 00:58:12,205 +it's very, very clear about the fact + +1306 +00:58:12,205 --> 00:58:15,667 +that you should not ask +for this SourceType camera + +1307 +00:58:15,667 --> 00:58:18,671 +unless you've checked first to +make sure there is a camera. + +1308 +00:58:18,671 --> 00:58:19,913 +So we'll just do that here. + +1309 +00:58:19,913 --> 00:58:24,580 +If +UIImagePickerController.isSourceTypeAvailable? + +1310 +00:58:26,459 --> 00:58:29,751 +And we're talking about the camera here. + +1311 +00:58:29,751 --> 00:58:32,723 +Then we'll put this camera here. + +1312 +00:58:36,375 --> 00:58:38,743 +Now when we run on our simulator, + +1313 +00:58:40,248 --> 00:58:41,607 +we now have a camera. + +1314 +00:58:41,607 --> 00:58:44,076 +Woo, it worked great! + +1315 +00:58:44,076 --> 00:58:47,227 +Okay, but we wanna see the +camera in action, don't we? + +1316 +00:58:47,227 --> 00:58:49,582 +So let's try running it on a device. + +1317 +00:58:49,582 --> 00:58:53,934 +I have a device attached +here, a Gold iPad. + +1318 +00:58:53,934 --> 00:58:56,323 +Let's run it on that and see what happens. + +1319 +00:58:57,798 --> 00:58:59,718 +Alright, we got a couple +of documents here. + +1320 +00:58:59,718 --> 00:59:02,345 +Let's go to our "Barn" document + +1321 +00:59:02,345 --> 00:59:03,609 +and let's bring up the camera. + +1322 +00:59:03,609 --> 00:59:05,252 +See the little camera picture there? + +1323 +00:59:05,252 --> 00:59:06,683 +Bring that up. + +1324 +00:59:07,539 --> 00:59:09,655 +Oh no, it crashed again! + +1325 +00:59:09,655 --> 00:59:10,488 +What? + +1326 +00:59:10,488 --> 00:59:12,325 +Look back here, oh no! + +1327 +00:59:12,325 --> 00:59:13,223 +And what does this say? + +1328 +00:59:13,223 --> 00:59:18,138 +It says "this app's Info.plist +must contain NSCameraUsage + +1329 +00:59:18,138 --> 00:59:20,692 +"with a key with a String +value to explain to the user + +1330 +00:59:20,692 --> 00:59:22,290 +"how the app uses this data." + +1331 +00:59:22,290 --> 00:59:23,297 +That's right. + +1332 +00:59:23,297 --> 00:59:25,040 +We can't just go willy-nilly, + +1333 +00:59:25,040 --> 00:59:27,589 +choosing people's cameras and microphones + +1334 +00:59:27,589 --> 00:59:29,085 +and other things on their device. + +1335 +00:59:29,085 --> 00:59:31,536 +We need to ask for permission. + +1336 +00:59:31,536 --> 00:59:33,290 +And part of asking permission + +1337 +00:59:33,290 --> 00:59:36,977 +is explaining why you +want to use this thing. + +1338 +00:59:36,977 --> 00:59:40,422 +So it's saying here go to +the Info.plist and add this. + +1339 +00:59:40,422 --> 00:59:43,152 +Let's do exactly that, Info.plist. + +1340 +00:59:43,152 --> 00:59:45,330 +The way we add an entry to the Info.plist + +1341 +00:59:45,330 --> 00:59:50,040 +is we right-click and say +"Add Row", here it is, + +1342 +00:59:50,040 --> 00:59:51,093 +then we just scroll down. + +1343 +00:59:51,093 --> 00:59:52,177 +This is a privacy thing + +1344 +00:59:52,177 --> 00:59:54,840 +so it's gonna be down +under privacy somewhere. + +1345 +00:59:54,840 --> 00:59:57,315 +Here it is, privacy, yep, the camera. + +1346 +00:59:57,315 --> 00:59:58,880 +See there, privacy, camera. + +1347 +00:59:58,880 --> 01:00:00,076 +A lot of privacy things here. + +1348 +01:00:00,076 --> 01:00:01,764 +Camera is the one we want. + +1349 +01:00:01,764 --> 01:00:05,244 +And we're just gonna explain +why we want the camera, + +1350 +01:00:05,244 --> 01:00:07,039 +why we want to use the camera, + +1351 +01:00:07,039 --> 01:00:12,039 +and we're gonna say "EmojiArt lets you set + +1352 +01:00:12,570 --> 01:00:17,570 +"the background of your +documents using the camera." + +1353 +01:00:17,996 --> 01:00:20,768 +It's our explanation as to why + +1354 +01:00:20,768 --> 01:00:24,580 +EmojiArt wants their camera right there. + +1355 +01:00:24,580 --> 01:00:26,313 +Let's try it again now. + +1356 +01:00:30,160 --> 01:00:33,718 +We'll go to "Barn" again, hit the camera. + +1357 +01:00:33,718 --> 01:00:35,960 +Now notice it's asking us + +1358 +01:00:35,960 --> 01:00:39,225 +do you want to allow the +user to use the camera? + +1359 +01:00:39,225 --> 01:00:42,444 +And it's got our little +explanation in there. + +1360 +01:00:42,444 --> 01:00:43,500 +It's great. + +1361 +01:00:43,500 --> 01:00:45,207 +So we'll say Allow. + +1362 +01:00:45,207 --> 01:00:48,320 +And then let's go take a picture here. + +1363 +01:00:48,320 --> 01:00:49,153 +Maybe that now. + +1364 +01:00:51,709 --> 01:00:54,467 +We'll say yeah, we wanna use this photo. + +1365 +01:00:54,467 --> 01:00:55,818 +Woo! + +1366 +01:00:55,818 --> 01:00:58,091 +It's our background image. + +1367 +01:00:58,091 --> 01:01:00,049 +So the camera was really +just as easy to do + +1368 +01:01:00,049 --> 01:01:01,346 +as the photo library. + +1369 +01:01:01,346 --> 01:01:02,641 +We just had to make sure the camera + +1370 +01:01:02,641 --> 01:01:04,280 +is actually available on our device + +1371 +01:01:04,280 --> 01:01:07,160 +and then provide that +little info to the user + +1372 +01:01:07,160 --> 01:01:08,593 +about why we wanna use it. + +1373 +01:01:09,506 --> 01:01:14,506 +So that is it for our +UIViewControllerRepresentable demo. + +1374 +01:01:14,651 --> 01:01:16,570 +Now you know how to put both Views + +1375 +01:01:16,570 --> 01:01:19,220 +and ViewControllers into your app. + +1376 +01:01:19,220 --> 01:01:21,710 +And that's all I have +for you this quarter. + +1377 +01:01:21,710 --> 01:01:24,827 +So now it's your turn to go +show us all that you've learned + +1378 +01:01:24,827 --> 01:01:26,798 +with your awesome final projects. + +1379 +01:01:26,798 --> 01:01:29,615 +And I look forward to +helping you down the stretch + +1380 +01:01:29,615 --> 01:01:31,680 +with any questions you have about that. + +1381 +01:01:31,680 --> 01:01:34,688 +And thanks for listening +to all these lectures. + +1382 +01:01:34,688 --> 01:01:38,255 +And good luck with your final project. + +1383 +01:01:38,255 --> 01:01:41,730 +- [Woman] For more, please +visit us at standford.edu. diff --git a/subtitles/en/Lecture 7. Multithreading EmojiArt.srt b/subtitles/en/Lecture 7. Multithreading EmojiArt.srt new file mode 100644 index 0000000..1147c3c --- /dev/null +++ b/subtitles/en/Lecture 7. Multithreading EmojiArt.srt @@ -0,0 +1,8994 @@ +1 +00:00:00,740 --> 00:00:03,490 +(peaceful music) + +2 +00:00:04,930 --> 00:00:06,630 +- [Presenter] Stanford University. + +3 +00:00:08,520 --> 00:00:13,290 +- [Paul] All right, +Lecture 7, Stanford CS193p, + +4 +00:00:13,290 --> 00:00:15,870 +Spring of 2020. + +5 +00:00:15,870 --> 00:00:18,950 +Today we're briefly gonna +talk about Colors and Images, + +6 +00:00:18,950 --> 00:00:20,423 +just a couple of minutes. + +7 +00:00:20,423 --> 00:00:22,780 +Then we're gonna dive +into our main topic today + +8 +00:00:22,780 --> 00:00:26,020 +which is multithreaded programming. + +9 +00:00:26,020 --> 00:00:28,620 +And then we're gonna have a humongous demo + +10 +00:00:28,620 --> 00:00:30,520 +and this demo's gonna +cover a lot of ground. + +11 +00:00:30,520 --> 00:00:34,810 +We're gonna somewhat review +MVVM by just developing + +12 +00:00:34,810 --> 00:00:36,973 +a completely separate app from scratch + +13 +00:00:36,973 --> 00:00:39,710 +and that you way you can +compare and contrast that app + +14 +00:00:39,710 --> 00:00:43,990 +with Memorize and it helps +you understand MVVM better. + +15 +00:00:43,990 --> 00:00:45,131 +And then we're gonna talk + +16 +00:00:45,131 --> 00:00:47,110 +about a bunch of miscellaneous topics + +17 +00:00:47,110 --> 00:00:50,327 +and of course we will demo multithreading + +18 +00:00:50,327 --> 00:00:52,513 +since that's our main topic of today. + +19 +00:00:53,890 --> 00:00:56,630 +So Colors and Images, let's +talk about Colors first. + +20 +00:00:56,630 --> 00:00:59,590 +There is a struct called +Color, as you know. + +21 +00:00:59,590 --> 00:01:01,140 +We've been using it so far. + +22 +00:01:01,140 --> 00:01:03,890 +And there's another thing called UIColor. + +23 +00:01:03,890 --> 00:01:05,850 +And you might wonder +why are these two things + +24 +00:01:05,850 --> 00:01:08,140 +that are just named so similarly? + +25 +00:01:08,140 --> 00:01:10,720 +Well a Color, as we learn, +and we talk about this + +26 +00:01:10,720 --> 00:01:15,470 +in the forums actually, can +kind of point different roles. + +27 +00:01:15,470 --> 00:01:17,220 +It can be a Color specifier, + +28 +00:01:17,220 --> 00:01:19,190 +like foregroundColor Color.green + +29 +00:01:19,190 --> 00:01:23,360 +or it can also be a +ShapeStyle, fill Color.blue. + +30 +00:01:23,360 --> 00:01:25,387 +And it could even be a +View, we haven't seen this + +31 +00:01:25,387 --> 00:01:27,120 +in any of our demos so far, + +32 +00:01:27,120 --> 00:01:29,700 +but it can be a View, Color.white. + +33 +00:01:29,700 --> 00:01:31,830 +You can have that appear +anywhere a View appears. + +34 +00:01:31,830 --> 00:01:33,740 +It's quite strange, and so like, kind of, + +35 +00:01:33,740 --> 00:01:37,620 +you get a rectangle filled +with white when you do that. + +36 +00:01:37,620 --> 00:01:40,760 +Now due to Color's multifaceted role + +37 +00:01:40,760 --> 00:01:42,650 +where it can do all +these different things, + +38 +00:01:42,650 --> 00:01:44,750 +it has somewhat limited API. + +39 +00:01:44,750 --> 00:01:48,310 +Mostly just creating Colors +and I think has some stuff + +40 +00:01:48,310 --> 00:01:51,643 +where you can compare Colors +but it's pretty limited. + +41 +00:01:52,650 --> 00:01:55,110 +So there's this other thing, UIColor. + +42 +00:01:55,110 --> 00:01:56,610 +This is the thing where you're actually + +43 +00:01:56,610 --> 00:01:58,780 +going to manipulate colors, + +44 +00:01:58,780 --> 00:02:00,610 +you're going to interrogate the color, + +45 +00:02:00,610 --> 00:02:05,610 +what's your RGB value, and it's +got a lot more system colors + +46 +00:02:05,710 --> 00:02:07,380 +and pre-built-in colors. + +47 +00:02:07,380 --> 00:02:09,700 +It's a much more powerful color class + +48 +00:02:09,700 --> 00:02:10,600 +than this Color thing. + +49 +00:02:10,600 --> 00:02:12,100 +Now it's not a chameleon. + +50 +00:02:12,100 --> 00:02:15,310 +It just is a little container +that represents a color + +51 +00:02:15,310 --> 00:02:17,710 +and it represents it in +a very particular way, + +52 +00:02:17,710 --> 00:02:18,760 +but that's what it is. + +53 +00:02:18,760 --> 00:02:20,890 +And if I'm ever gonna do +any color manipulation, + +54 +00:02:20,890 --> 00:02:24,400 +which you are gonna do, by the +way, in your assignment five. + +55 +00:02:24,400 --> 00:02:26,500 +Not next week but the week after, + +56 +00:02:26,500 --> 00:02:29,020 +you're gonna wanna use UIColor. + +57 +00:02:29,020 --> 00:02:31,420 +But the great thing is once +you've built the UIColor + +58 +00:02:31,420 --> 00:02:33,810 +and transformed it or do +whatever you wanna do to it + +59 +00:02:33,810 --> 00:02:36,170 +to make it the way you +want, now you can just say + +60 +00:02:36,170 --> 00:02:39,350 +Color uiColor: and specify that color + +61 +00:02:39,350 --> 00:02:41,560 +and you can use it in all the ways above, + +62 +00:02:41,560 --> 00:02:44,459 +as a specifier, a View, whatever. + +63 +00:02:44,459 --> 00:02:46,550 +UIColor starts with UI. + +64 +00:02:46,550 --> 00:02:50,650 +That's because it comes from +the old pre-SwiftUI world. + +65 +00:02:50,650 --> 00:02:53,400 +Things that start with UI are from UIKit. + +66 +00:02:53,400 --> 00:02:56,200 +But it was so good at manipulating colors, + +67 +00:02:56,200 --> 00:03:00,120 +yeah, they just brought it +into SwiftUI just like it was. + +68 +00:03:00,120 --> 00:03:02,720 +Now a similar sort of dichotomy happened + +69 +00:03:02,720 --> 00:03:05,034 +with Image and UIImage. + +70 +00:03:05,034 --> 00:03:08,323 +So Image in SwiftUI is primarily a View, + +71 +00:03:09,460 --> 00:03:11,490 +and it's a View that displays an image. + +72 +00:03:11,490 --> 00:03:14,930 +It's not something that you +would make a var of type Image + +73 +00:03:14,930 --> 00:03:16,240 +and it holds an image. + +74 +00:03:16,240 --> 00:03:17,550 +It is a View. + +75 +00:03:17,550 --> 00:03:20,490 +So this Image View you +can specify what image + +76 +00:03:20,490 --> 00:03:23,710 +you want it to display +in a number of ways. + +77 +00:03:23,710 --> 00:03:26,340 +One way is by just giving it a String, + +78 +00:03:26,340 --> 00:03:29,280 +and it will use that +as the name of an image + +79 +00:03:29,280 --> 00:03:33,290 +that it finds in your +Assets.xcassets file. + +80 +00:03:33,290 --> 00:03:36,090 +If you look in Xcode +where all your files are, + +81 +00:03:36,090 --> 00:03:37,750 +there's a file we haven't +talked about in there, + +82 +00:03:37,750 --> 00:03:40,810 +Assets.xcassets, Xcode assets. + +83 +00:03:40,810 --> 00:03:43,240 +And if you look at it you'll +see that it's just a place + +84 +00:03:43,240 --> 00:03:45,690 +to store images in lots +of different formats + +85 +00:03:45,690 --> 00:03:48,650 +and you can get them by name +by saying Image of the name. + +86 +00:03:48,650 --> 00:03:52,500 +That's kind of the most +basic way to access an image. + +87 +00:03:52,500 --> 00:03:55,760 +There are also though +a ton of system images. + +88 +00:03:55,760 --> 00:03:58,850 +And you get this one by +saying Image systemName: + +89 +00:03:58,850 --> 00:04:00,250 +and then the name. + +90 +00:04:00,250 --> 00:04:02,010 +Now how do you find +out what all these are? + +91 +00:04:02,010 --> 00:04:04,120 +Well, you're gonna need to download an app + +92 +00:04:04,120 --> 00:04:07,140 +from developer.apple.com/design + +93 +00:04:07,140 --> 00:04:10,470 +called SF Symbols and it +has all of them listed. + +94 +00:04:10,470 --> 00:04:12,920 +You can search through them by name, + +95 +00:04:12,920 --> 00:04:15,693 +the names pretty much +encapsulate what they are. + +96 +00:04:16,600 --> 00:04:17,720 +When you're there, by the way, + +97 +00:04:17,720 --> 00:04:19,800 +at developer.apple.com/design, + +98 +00:04:19,800 --> 00:04:21,810 +there's a document you'll +see right on that page + +99 +00:04:21,810 --> 00:04:23,880 +called the Human Interface Guidelines. + +100 +00:04:23,880 --> 00:04:25,810 +You really wanna read that document. + +101 +00:04:25,810 --> 00:04:27,180 +I really (chuckles) should have made it + +102 +00:04:27,180 --> 00:04:29,100 +reading assignment number four. + +103 +00:04:29,100 --> 00:04:31,750 +I might go back and still do +that, but you should read it. + +104 +00:04:31,750 --> 00:04:34,240 +It's an absolute must +read if you ever want + +105 +00:04:34,240 --> 00:04:35,720 +to do an App Store submission. + +106 +00:04:35,720 --> 00:04:39,600 +It talks about how your UI is +supposed to do certain things + +107 +00:04:39,600 --> 00:04:42,720 +so that all UIs in all +apps are doing these things + +108 +00:04:42,720 --> 00:04:45,830 +in the same way and the user +gets a consistent experience. + +109 +00:04:45,830 --> 00:04:48,190 +Super important, and, not +just to read that document, + +110 +00:04:48,190 --> 00:04:50,850 +to really understand all of +the things that are in it + +111 +00:04:50,850 --> 00:04:52,160 +so when you go to write your app + +112 +00:04:52,160 --> 00:04:54,760 +and submit it to the App +Store it doesn't get rejected + +113 +00:04:54,760 --> 00:04:57,940 +for violating these Human +Interface Guidelines. + +114 +00:04:57,940 --> 00:05:00,930 +If you use the system +name images, by the way, + +115 +00:05:00,930 --> 00:05:02,770 +you can control how large they are + +116 +00:05:02,770 --> 00:05:05,230 +with the .imageScale View modifier. + +117 +00:05:05,230 --> 00:05:06,800 +It's a little bit hidden there + +118 +00:05:06,800 --> 00:05:09,385 +'cause you don't do it on +somewhere in the image. + +119 +00:05:09,385 --> 00:05:11,220 +So there's actually a View modifier. + +120 +00:05:11,220 --> 00:05:12,760 +So go take a look at that. + +121 +00:05:12,760 --> 00:05:14,870 +And also just a quick +note, the system images + +122 +00:05:14,870 --> 00:05:16,970 +are really good to use as masks. + +123 +00:05:16,970 --> 00:05:18,730 +So like if you have a gradient, + +124 +00:05:18,730 --> 00:05:22,060 +you can have it shine +through the system image + +125 +00:05:22,060 --> 00:05:24,410 +and that can give you +some really cool effects. + +126 +00:05:25,940 --> 00:05:28,680 +So UIImage, that's the +thing that if you had a var + +127 +00:05:28,680 --> 00:05:31,360 +that was gonna hold an image +in it, like a JPEG image, + +128 +00:05:31,360 --> 00:05:33,120 +it would be of type UIImage. + +129 +00:05:33,120 --> 00:05:36,430 +Again, comes from UIKit, +it was so good (chuckles) + +130 +00:05:36,430 --> 00:05:38,820 +at handling images, +there was just no reason + +131 +00:05:38,820 --> 00:05:42,470 +to try and duplicate it +all in the Image View. + +132 +00:05:42,470 --> 00:05:44,120 +And so they just brought it in + +133 +00:05:44,120 --> 00:05:47,201 +and UIImage can do multiple file formats, + +134 +00:05:47,201 --> 00:05:48,710 +JPEGs, GIF, PNGs. + +135 +00:05:48,710 --> 00:05:52,010 +It has transformation +primitives, scaling, all these, + +136 +00:05:52,010 --> 00:05:54,970 +it can do animated images, all that. + +137 +00:05:54,970 --> 00:05:57,920 +And once you've built a +UIImage up to what you want + +138 +00:05:57,920 --> 00:06:02,920 +from whatever JPEG file or +whatever you built it from, + +139 +00:06:03,070 --> 00:06:06,234 +then you can say Image uiImage:, + +140 +00:06:06,234 --> 00:06:09,940 +the UIImage and present it as a View. + +141 +00:06:09,940 --> 00:06:12,930 +So similar kind of, +with Color and UIColor, + +142 +00:06:12,930 --> 00:06:14,190 +Image and UIImage. + +143 +00:06:16,110 --> 00:06:18,603 +All right, main thing of +the day, multithreading. + +144 +00:06:19,673 --> 00:06:24,673 +Now multithreading can +be used to build systems + +145 +00:06:25,250 --> 00:06:28,090 +of parallel computing +where you've got an app + +146 +00:06:28,090 --> 00:06:29,810 +and it's doing multiple +things at the same time. + +147 +00:06:29,810 --> 00:06:31,240 +Maybe they depend on each other, + +148 +00:06:31,240 --> 00:06:34,710 +you want to manage those +dependencies, all these things. + +149 +00:06:34,710 --> 00:06:36,710 +But we're only gonna +talk about multithreading + +150 +00:06:36,710 --> 00:06:40,610 +in this class in one very important niche + +151 +00:06:40,610 --> 00:06:45,123 +that it can satisfy, which +is not blocking the UI. + +152 +00:06:46,110 --> 00:06:48,290 +And we're going to not block the UI + +153 +00:06:48,290 --> 00:06:50,940 +by having all the stuff +that would block the UI + +154 +00:06:50,940 --> 00:06:53,390 +on a different thread of execution. + +155 +00:06:53,390 --> 00:06:56,950 +Now it is never okay for +your UI to be blocked. + +156 +00:06:56,950 --> 00:06:59,050 +If someone reaches with their finger + +157 +00:06:59,050 --> 00:07:02,030 +to scroll something or tap on a button, + +158 +00:07:02,030 --> 00:07:03,730 +your UI has to be ready to do it. + +159 +00:07:03,730 --> 00:07:05,247 +It cannot be saying, "Oh, I'm sorry. + +160 +00:07:05,247 --> 00:07:07,387 +"I'm off doing something else for a second + +161 +00:07:07,387 --> 00:07:08,820 +"or so, I'll be right back." + +162 +00:07:08,820 --> 00:07:10,183 +It has to instantly do it. + +163 +00:07:11,730 --> 00:07:14,090 +But sometimes you need +to do those slow things. + +164 +00:07:14,090 --> 00:07:16,850 +You need to do some huge +machine learning calculation + +165 +00:07:16,850 --> 00:07:19,300 +or something, or you need +to go out over the network + +166 +00:07:19,300 --> 00:07:20,690 +and that's gonna take time. + +167 +00:07:20,690 --> 00:07:22,430 +There's just no avoiding that time. + +168 +00:07:22,430 --> 00:07:25,413 +So how during that time are +you gonna not block your UI? + +169 +00:07:26,280 --> 00:07:27,113 +Well, we're gonna do that + +170 +00:07:27,113 --> 00:07:29,190 +by using different threads of execution. + +171 +00:07:29,190 --> 00:07:32,700 +Now I'm gonna assume most +of you know what a thread is + +172 +00:07:32,700 --> 00:07:35,110 +but I'll just quickly talk about it. + +173 +00:07:35,110 --> 00:07:37,590 +Most modern operating +systems have this ability + +174 +00:07:37,590 --> 00:07:40,280 +to say this code should execute + +175 +00:07:40,280 --> 00:07:42,750 +on its own thread of execution. + +176 +00:07:42,750 --> 00:07:45,380 +And then you can have +multiple threads of execution + +177 +00:07:45,380 --> 00:07:47,320 +all executing simultaneously. + +178 +00:07:47,320 --> 00:07:50,760 +Now they may not actually +be executing simultaneously. + +179 +00:07:50,760 --> 00:07:54,200 +You know, if you have +multiple core processors + +180 +00:07:54,200 --> 00:07:56,890 +or a multi-processor or +something, they might be. + +181 +00:07:56,890 --> 00:07:59,280 +But sometimes you just have a single core + +182 +00:07:59,280 --> 00:08:01,670 +or not enough cores and +so it's actually switching + +183 +00:08:01,670 --> 00:08:04,500 +back and forth between them +really quickly, not doing it. + +184 +00:08:04,500 --> 00:08:05,840 +But you don't care about any of that. + +185 +00:08:05,840 --> 00:08:08,460 +To you, it just appears that +you've got different pieces + +186 +00:08:08,460 --> 00:08:10,420 +of code executing simultaneously. + +187 +00:08:10,420 --> 00:08:13,920 +They're running at the exact +same time somehow, madly. + +188 +00:08:13,920 --> 00:08:18,550 +Now this can be a little +bit complicated to manage + +189 +00:08:18,550 --> 00:08:20,560 +in terms of as a programmer deciding, + +190 +00:08:20,560 --> 00:08:22,140 +well this one wants to be running + +191 +00:08:22,140 --> 00:08:24,920 +on this thread of execution, +this one over here. + +192 +00:08:24,920 --> 00:08:27,850 +So we really need some help in making + +193 +00:08:27,850 --> 00:08:31,100 +this multithreaded code +readable and understandable + +194 +00:08:31,100 --> 00:08:33,650 +by mere mortals like us + +195 +00:08:33,650 --> 00:08:36,410 +and we need this because this time, + +196 +00:08:36,410 --> 00:08:38,800 +this thing about things +running at the same time + +197 +00:08:38,800 --> 00:08:41,450 +adds this fourth dimensions to our code + +198 +00:08:41,450 --> 00:08:43,580 +that's hard for us to grok. + +199 +00:08:43,580 --> 00:08:45,770 +Swift solves this complexity issue + +200 +00:08:45,770 --> 00:08:48,720 +using something called queues. + +201 +00:08:48,720 --> 00:08:53,100 +Now a queue is nothing more +than a bunch of blocks of code + +202 +00:08:53,100 --> 00:08:56,010 +that are sitting in line +just patiently waiting + +203 +00:08:56,010 --> 00:08:59,150 +to get a thread of execution +that will go and run them. + +204 +00:08:59,150 --> 00:09:01,890 +Now and by queue I mean +the same thing as queue + +205 +00:09:01,890 --> 00:09:04,427 +like a queue at the +movies or at least queue + +206 +00:09:04,427 --> 00:09:06,030 +that used to be at the movies + +207 +00:09:06,030 --> 00:09:07,760 +before they closed all the +movie theaters (chuckles) + +208 +00:09:07,760 --> 00:09:10,690 +for coronavirus, but, you know, a line + +209 +00:09:10,690 --> 00:09:12,810 +where people are standing in +line, the same thing here. + +210 +00:09:12,810 --> 00:09:14,370 +These are just blocks of code + +211 +00:09:14,370 --> 00:09:17,690 +waiting in line to get executed. + +212 +00:09:17,690 --> 00:09:20,270 +So with Swift we don't +think about threads. + +213 +00:09:20,270 --> 00:09:21,310 +We don't even think about 'em. + +214 +00:09:21,310 --> 00:09:23,270 +All we think about is queues. + +215 +00:09:23,270 --> 00:09:26,240 +We let the system come +up with all the threads + +216 +00:09:26,240 --> 00:09:28,960 +and all that stuff to take +things off these queues + +217 +00:09:28,960 --> 00:09:30,730 +and execute them, that's up to the system. + +218 +00:09:30,730 --> 00:09:33,840 +All we think about is the +queues and the blocks of code + +219 +00:09:33,840 --> 00:09:36,173 +we want to plop on those queues. + +220 +00:09:37,300 --> 00:09:40,710 +We specify these blocks of +code that go on the queues + +221 +00:09:40,710 --> 00:09:44,450 +using closures, functions as arguments. + +222 +00:09:44,450 --> 00:09:47,870 +We'll see how this works, what +the code looks like for this + +223 +00:09:47,870 --> 00:09:50,460 +but let's just quickly talk about queues + +224 +00:09:50,460 --> 00:09:52,367 +and what queues are available first. + +225 +00:09:52,367 --> 00:09:56,640 +And the most important queue +in all the world of iOS + +226 +00:09:56,640 --> 00:09:59,180 +is called the main queue. + +227 +00:09:59,180 --> 00:10:02,400 +Now this is the queue that has +all the blocks of code on it + +228 +00:10:02,400 --> 00:10:04,880 +that have anything to do with UI. + +229 +00:10:04,880 --> 00:10:07,350 +Anytime you want to do +something in the UI, + +230 +00:10:07,350 --> 00:10:09,670 +you have to use the main queue. + +231 +00:10:09,670 --> 00:10:13,410 +It is absolutely unequivocally an error + +232 +00:10:13,410 --> 00:10:17,870 +to do UI in any block of +code that is not executing, + +233 +00:10:17,870 --> 00:10:20,720 +was not chosen from, the main queue. + +234 +00:10:20,720 --> 00:10:24,300 +So when you tap on a screen, +that is going to execute code + +235 +00:10:24,300 --> 00:10:25,393 +on the main queue. + +236 +00:10:26,410 --> 00:10:30,930 +When you do anything that +draws in the UI in any way, + +237 +00:10:30,930 --> 00:10:33,350 +it's going to get initiated +from the main queue. + +238 +00:10:33,350 --> 00:10:35,820 +There is some stuff like animation + +239 +00:10:35,820 --> 00:10:38,150 +where all the calculations +of the animation, + +240 +00:10:38,150 --> 00:10:41,463 +the inter-frame, the +animatableData that we did in, + +241 +00:10:41,463 --> 00:10:44,410 +that is going to happen in +another queue off the main queue. + +242 +00:10:44,410 --> 00:10:47,480 +But it's all gonna get coordinated +back onto the main queue + +243 +00:10:47,480 --> 00:10:50,010 +to do the drawing, so +the stuff all happens + +244 +00:10:50,010 --> 00:10:51,660 +without smashing into each other. + +245 +00:10:54,230 --> 00:10:57,320 +So where do we do the +long-lived stuff then, + +246 +00:10:57,320 --> 00:11:00,430 +the non-UI stuff, well, +the best place to do it + +247 +00:11:00,430 --> 00:11:03,700 +is in this pile of background queues + +248 +00:11:03,700 --> 00:11:06,410 +that the system makes available to you. + +249 +00:11:06,410 --> 00:11:08,470 +So this is where we're gonna do anything + +250 +00:11:08,470 --> 00:11:10,390 +that's gonna take a long +time like a network call + +251 +00:11:10,390 --> 00:11:12,280 +or some, like I said, +machine learning (chuckles) + +252 +00:11:12,280 --> 00:11:15,210 +or some other analysis +that's gonna take, you know, + +253 +00:11:15,210 --> 00:11:18,113 +more than a millisecond or so to do. + +254 +00:11:19,380 --> 00:11:23,280 +The system has, it +manages a bunch of threads + +255 +00:11:23,280 --> 00:11:27,670 +to go pull blocks of code off +of these background queues + +256 +00:11:27,670 --> 00:11:29,050 +and run them for you. + +257 +00:11:29,050 --> 00:11:31,360 +So things that you put on +these background queues, + +258 +00:11:31,360 --> 00:11:33,920 +they all seem to almost +be running simultaneously + +259 +00:11:33,920 --> 00:11:35,910 +and of course they're +running simultaneously + +260 +00:11:35,910 --> 00:11:37,510 +with what's on the main queue. + +261 +00:11:37,510 --> 00:11:40,510 +But of course, the main queue +always gets higher priority. + +262 +00:11:40,510 --> 00:11:43,150 +If someone taps or if you +put your own block of code + +263 +00:11:43,150 --> 00:11:48,150 +on this main queue, it's +gonna run much more quickly + +264 +00:11:48,240 --> 00:11:50,730 +and with more attention than anything + +265 +00:11:50,730 --> 00:11:52,453 +on these background queues. + +266 +00:11:53,290 --> 00:11:55,720 +The whole system that does all this + +267 +00:11:55,720 --> 00:11:57,740 +is called Grand Central Dispatch + +268 +00:11:57,740 --> 00:12:01,590 +because it's dispatching +the code from the queues + +269 +00:12:01,590 --> 00:12:05,110 +to be executed by the threads. + +270 +00:12:05,110 --> 00:12:07,320 +And it has a number of different functions + +271 +00:12:07,320 --> 00:12:09,660 +in there in Grand Central Dispatch, + +272 +00:12:09,660 --> 00:12:12,710 +but really it boils down to +these two fundamental tasks + +273 +00:12:12,710 --> 00:12:14,580 +that you're doing with GCD. + +274 +00:12:14,580 --> 00:12:16,800 +One is getting a queue + +275 +00:12:16,800 --> 00:12:19,400 +and two, plopping a block +of code on the queue. + +276 +00:12:19,400 --> 00:12:24,400 +And that's pretty much +99% of what GCD is about. + +277 +00:12:24,540 --> 00:12:26,510 +There's more stuff in there coordinating + +278 +00:12:26,510 --> 00:12:28,500 +with when things are +happening on multiple queues, + +279 +00:12:28,500 --> 00:12:31,240 +but for our purposes, +especially for the purposes + +280 +00:12:31,240 --> 00:12:36,240 +of keeping long-lived things +off of the UI main queue, + +281 +00:12:36,350 --> 00:12:38,323 +these are the two main things we need. + +282 +00:12:39,340 --> 00:12:41,560 +So let's talk about the +first of these two things + +283 +00:12:41,560 --> 00:12:45,690 +which is creating or +getting access to a queue. + +284 +00:12:45,690 --> 00:12:48,470 +Now the first one is simple, +that's the main queue. + +285 +00:12:48,470 --> 00:12:51,200 +You're just gonna use this +simple DispatchQueue.main, + +286 +00:12:51,200 --> 00:12:53,000 +right, main is the static function + +287 +00:12:53,000 --> 00:12:54,830 +in the struct DispatchQueue. + +288 +00:12:54,830 --> 00:12:56,710 +And that is the queue you're gonna use + +289 +00:12:56,710 --> 00:12:58,780 +whenever you want to draw in the UI. + +290 +00:12:58,780 --> 00:13:01,280 +Couldn't be simpler, that's all you do. + +291 +00:13:01,280 --> 00:13:03,020 +What about all the background queues? + +292 +00:13:03,020 --> 00:13:05,470 +For that one you're gonna +call this static function + +293 +00:13:05,470 --> 00:13:07,800 +in DispatchQueue called global + +294 +00:13:07,800 --> 00:13:12,300 +which takes an argument qos +which is quality of service + +295 +00:13:12,300 --> 00:13:14,550 +which is kind of like priority. + +296 +00:13:14,550 --> 00:13:17,550 +Essentially how much do we want the system + +297 +00:13:17,550 --> 00:13:21,810 +to pay attention to the +blocks of code on this queue. + +298 +00:13:21,810 --> 00:13:25,880 +And the four options you have +here are userInteractive. + +299 +00:13:25,880 --> 00:13:27,860 +This is for things like +you're in the middle + +300 +00:13:27,860 --> 00:13:30,480 +of dragging something across the screen + +301 +00:13:30,480 --> 00:13:33,030 +and you need to calculate something. + +302 +00:13:33,030 --> 00:13:36,430 +It might take a little bit, +so you can't make the drag + +303 +00:13:36,430 --> 00:13:39,110 +be jaggy but you need +that information now! + +304 +00:13:39,110 --> 00:13:42,073 +So this is a super high +priority (chuckles) queue. + +305 +00:13:42,073 --> 00:13:44,400 +It's gonna get serviced a lot. + +306 +00:13:44,400 --> 00:13:46,280 +Then there's userInitiated. + +307 +00:13:46,280 --> 00:13:47,890 +Here you're not in the middle of a drag, + +308 +00:13:47,890 --> 00:13:50,137 +but the user did just tap on something. + +309 +00:13:50,137 --> 00:13:53,190 +"Do this for me," so you +need to do this right now. + +310 +00:13:53,190 --> 00:13:56,310 +Then there's utility which +is the user didn't just ask + +311 +00:13:56,310 --> 00:13:58,730 +for this, but it needs to be done. + +312 +00:13:58,730 --> 00:14:00,410 +So this is pretty high priority, + +313 +00:14:00,410 --> 00:14:01,640 +but it's not like the user + +314 +00:14:01,640 --> 00:14:03,370 +just clicked a button +and wants this done now. + +315 +00:14:03,370 --> 00:14:06,210 +And then there's background +which is really low priority. + +316 +00:14:06,210 --> 00:14:08,780 +This is, you know, I'm +cleaning up my database + +317 +00:14:08,780 --> 00:14:11,356 +of old cruft or something that's +going on in the background + +318 +00:14:11,356 --> 00:14:14,040 +that really has nothing to do +with what the user perceives + +319 +00:14:14,040 --> 00:14:15,760 +to be their app, but it's something my app + +320 +00:14:15,760 --> 00:14:19,203 +needs to do to have proper +operation or whatever. + +321 +00:14:20,407 --> 00:14:23,810 +And that's it, that's how +you get a queue, super easy. + +322 +00:14:23,810 --> 00:14:26,157 +GCD you're gonna find is amazingly simple + +323 +00:14:26,157 --> 00:14:28,317 +and it's really simple +to get ahold of a queue. + +324 +00:14:28,317 --> 00:14:29,890 +You're either gonna do the main queue + +325 +00:14:29,890 --> 00:14:32,363 +or one of these global background queues. + +326 +00:14:33,750 --> 00:14:37,470 +The second thing is plopping +a closure onto a queue. + +327 +00:14:37,470 --> 00:14:38,440 +Well how are we gonna do that? + +328 +00:14:38,440 --> 00:14:40,680 +Well let's say I have my +queue, either the main queue + +329 +00:14:40,680 --> 00:14:42,410 +or one of these global queues. + +330 +00:14:42,410 --> 00:14:45,290 +And I'm either gonna +call this function async + +331 +00:14:45,290 --> 00:14:47,487 +or the function sync on that queue. + +332 +00:14:47,487 --> 00:14:50,050 +And the argument is just a closure + +333 +00:14:50,050 --> 00:14:52,470 +and it's a function +that takes no arguments + +334 +00:14:52,470 --> 00:14:54,090 +and returns no arguments. + +335 +00:14:54,090 --> 00:14:56,710 +And inside there I'm gonna +put whatever code I want + +336 +00:14:56,710 --> 00:14:59,450 +to be executed on that queue. + +337 +00:14:59,450 --> 00:15:03,380 +Now the second one of +these, the .sync, blocks. + +338 +00:15:03,380 --> 00:15:06,190 +So it blocks and waits 'til that queue, + +339 +00:15:06,190 --> 00:15:07,120 +the green queue right there, + +340 +00:15:07,120 --> 00:15:10,560 +it waits until it has +taken this block of code + +341 +00:15:10,560 --> 00:15:13,960 +off of its queue and +executed it to completion. + +342 +00:15:13,960 --> 00:15:15,520 +Then it's gonna continue. + +343 +00:15:15,520 --> 00:15:19,500 +So we would never call +queue.sync in UI code + +344 +00:15:19,500 --> 00:15:21,660 +because it would block the UI. + +345 +00:15:21,660 --> 00:15:24,740 +In fact, it's rare to +call this .sync at all. + +346 +00:15:24,740 --> 00:15:26,900 +So we're almost always using .async + +347 +00:15:26,900 --> 00:15:28,670 +which means just take this block of code, + +348 +00:15:28,670 --> 00:15:31,560 +throw it on this other +queue, and just keep going. + +349 +00:15:31,560 --> 00:15:32,920 +And so that means that whatever's + +350 +00:15:32,920 --> 00:15:34,680 +in that curly braces there, + +351 +00:15:34,680 --> 00:15:37,530 +it's gonna be executed +some time in the future. + +352 +00:15:37,530 --> 00:15:39,700 +I don't know when, it's +whenever that queue + +353 +00:15:39,700 --> 00:15:40,580 +gets around to it. + +354 +00:15:40,580 --> 00:15:42,373 +Now hopefully if that's the main queue, + +355 +00:15:42,373 --> 00:15:43,206 +it's gonna be pretty soon + +356 +00:15:43,206 --> 00:15:46,963 +but even that's not a +locked, solid guarantee. + +357 +00:15:47,850 --> 00:15:50,543 +So your code has to be +tolerant of the fact + +358 +00:15:50,543 --> 00:15:53,030 +that when you say queue.async blah, + +359 +00:15:53,030 --> 00:15:56,730 +whatever's in the blah +might not be executed for, + +360 +00:15:56,730 --> 00:15:59,950 +you know, many milliseconds, +possibly even longer. + +361 +00:15:59,950 --> 00:16:01,930 +So that's a little bit of thinking + +362 +00:16:01,930 --> 00:16:05,940 +you have to comprehend that +as you write your code. + +363 +00:16:05,940 --> 00:16:07,490 +But async is the one we usually do. + +364 +00:16:07,490 --> 00:16:10,020 +We're just plopping these blocks of code + +365 +00:16:10,020 --> 00:16:13,723 +onto these other queues to +get them to get executed. + +366 +00:16:15,070 --> 00:16:17,340 +Besides async and sync, +there are some other ones. + +367 +00:16:17,340 --> 00:16:20,310 +asyncAfter, which will do the async + +368 +00:16:20,310 --> 00:16:23,320 +but after a little delay +so that you can wait + +369 +00:16:23,320 --> 00:16:26,270 +to have it executed, but mostly +we're gonna be doing async. + +370 +00:16:28,130 --> 00:16:30,320 +Beauty of this GCD API, + +371 +00:16:30,320 --> 00:16:31,820 +when you combine these two things, + +372 +00:16:31,820 --> 00:16:34,750 +having a queue and async +to plop it on there + +373 +00:16:34,750 --> 00:16:37,827 +is when you're nesting these +things inside of each other. + +374 +00:16:37,827 --> 00:16:39,510 +Now let's look at an example here. + +375 +00:16:39,510 --> 00:16:42,870 +So I'm doing DispatchQueue +global userInitiated + +376 +00:16:42,870 --> 00:16:44,570 +so this is something +the user asked me to do + +377 +00:16:44,570 --> 00:16:46,600 +but I'm gonna do it on +a background thread, + +378 +00:16:46,600 --> 00:16:49,530 +not on the main queue. + +379 +00:16:49,530 --> 00:16:52,230 +So I'd call that async +with a block of code + +380 +00:16:52,230 --> 00:16:54,020 +and in that block of code at the beginning + +381 +00:16:54,020 --> 00:16:54,953 +I'm gonna be doing something + +382 +00:16:54,953 --> 00:16:56,510 +that might take a very long time. + +383 +00:16:56,510 --> 00:16:58,740 +Maybe I'm accessing +something on the network + +384 +00:16:58,740 --> 00:17:00,550 +or doing some calculation. + +385 +00:17:00,550 --> 00:17:02,840 +And it's fine to do because +I'm not doing this code, + +386 +00:17:02,840 --> 00:17:05,770 +this curly brace that +has started right there + +387 +00:17:05,770 --> 00:17:07,560 +is not doing something on the main queue. + +388 +00:17:07,560 --> 00:17:10,900 +So that's fine to take as +long as I want right here. + +389 +00:17:10,900 --> 00:17:13,400 +But this longtime thing that we're doing, + +390 +00:17:13,400 --> 00:17:15,740 +when it comes back +maybe it's gonna require + +391 +00:17:15,740 --> 00:17:16,780 +a change to the UI. + +392 +00:17:16,780 --> 00:17:19,270 +Maybe I fetched an image and +now I wanna put that image + +393 +00:17:19,270 --> 00:17:22,320 +on the UI, but we can't do that UI here + +394 +00:17:22,320 --> 00:17:23,880 +because we are currently + +395 +00:17:23,880 --> 00:17:25,670 +on one of these global background queues. + +396 +00:17:25,670 --> 00:17:28,260 +We can't do UI on this queue. + +397 +00:17:28,260 --> 00:17:31,420 +So this code that we +posted async to that queue + +398 +00:17:31,420 --> 00:17:33,230 +can't do UI here. + +399 +00:17:33,230 --> 00:17:35,570 +But that's no problem, +let's just turn around + +400 +00:17:35,570 --> 00:17:38,600 +and post a block of code +that does do the UI thing + +401 +00:17:38,600 --> 00:17:39,540 +back on the main queue. + +402 +00:17:39,540 --> 00:17:42,280 +And the main queue eventually +will get through its queue + +403 +00:17:42,280 --> 00:17:45,060 +and get to this one and execute it. + +404 +00:17:45,060 --> 00:17:47,270 +And again, the main queue, high priority. + +405 +00:17:47,270 --> 00:17:48,990 +It's probably not gonna take long. + +406 +00:17:48,990 --> 00:17:51,200 +It might be nothing on the +queue when you put it on there, + +407 +00:17:51,200 --> 00:17:54,180 +and boom it just runs really quickly. + +408 +00:17:54,180 --> 00:17:57,150 +But conceptually the point is we're taking + +409 +00:17:57,150 --> 00:17:58,697 +this block of code and +telling the main queue, + +410 +00:17:58,697 --> 00:18:00,770 +"Hey, you go run this thing." + +411 +00:18:00,770 --> 00:18:02,650 +And so you can do UI in there. + +412 +00:18:02,650 --> 00:18:06,650 +This makes asynchronous +code almost look synchronous + +413 +00:18:06,650 --> 00:18:08,310 +but they're not quite. + +414 +00:18:08,310 --> 00:18:12,035 +First outer block there, the +outer yellow DispatchQueue + +415 +00:18:12,035 --> 00:18:14,810 +async is, it could take a long time. + +416 +00:18:14,810 --> 00:18:16,580 +And so that inner line +might not be happening + +417 +00:18:16,580 --> 00:18:18,020 +for 10 seconds. + +418 +00:18:18,020 --> 00:18:21,040 +And what if the user is +like totally navigating away + +419 +00:18:21,040 --> 00:18:23,160 +from this in their UI, +they're just not even, + +420 +00:18:23,160 --> 00:18:25,550 +it took so long they +don't even care anymore. + +421 +00:18:25,550 --> 00:18:26,617 +And then you come back and you're like, + +422 +00:18:26,617 --> 00:18:28,500 +"Oh, now I want to put this image up," + +423 +00:18:28,500 --> 00:18:29,960 +but the user doesn't care +about that image anymore. + +424 +00:18:29,960 --> 00:18:32,360 +They're off doing +something else in the app. + +425 +00:18:32,360 --> 00:18:33,800 +That's why I'm saying you +have to think a little bit + +426 +00:18:33,800 --> 00:18:37,410 +about the time, but at +least it makes it read, + +427 +00:18:37,410 --> 00:18:38,880 +from a conceptual standpoint, + +428 +00:18:38,880 --> 00:18:41,713 +looks almost like +synchronous code right here. + +429 +00:18:42,960 --> 00:18:45,600 +This DispatchQueue.main.async that we saw, + +430 +00:18:45,600 --> 00:18:48,240 +you're gonna often do that. + +431 +00:18:48,240 --> 00:18:49,990 +And the reason you're gonna often do that + +432 +00:18:49,990 --> 00:18:51,590 +when you're doing asynchronous programming + +433 +00:18:51,590 --> 00:18:53,810 +is you're gonna be doing +things in the background + +434 +00:18:53,810 --> 00:18:57,210 +that are gonna result in things +that are gonna affect the UI + +435 +00:18:57,210 --> 00:18:59,710 +and so you're gonna have +to Dispatch main async + +436 +00:18:59,710 --> 00:19:03,830 +back to the UI to do the +UI results of those things. + +437 +00:19:03,830 --> 00:19:05,730 +However you're not actually gonna call + +438 +00:19:05,730 --> 00:19:09,910 +DispatchQueue.global qos very often. + +439 +00:19:09,910 --> 00:19:11,350 +Why aren't you gonna call that very much? + +440 +00:19:11,350 --> 00:19:15,400 +Well, that's because there +are higher-level APIs + +441 +00:19:15,400 --> 00:19:18,750 +for managing this background activities + +442 +00:19:18,750 --> 00:19:19,840 +that you're gonna be calling. + +443 +00:19:19,840 --> 00:19:22,960 +For example, if you +wanted to fetch an image + +444 +00:19:22,960 --> 00:19:24,690 +over the network which we're gonna do + +445 +00:19:24,690 --> 00:19:28,000 +by doing Dispatch global +in the demo later today, + +446 +00:19:28,000 --> 00:19:28,930 +but if you wanted to do it, + +447 +00:19:28,930 --> 00:19:31,630 +you really would use this +thing called URLSession. + +448 +00:19:31,630 --> 00:19:36,410 +So URLSession is a struct +and it takes the information + +449 +00:19:36,410 --> 00:19:38,240 +about the URL you want and it goes off + +450 +00:19:38,240 --> 00:19:43,180 +and it puts something +on the global QoS queues + +451 +00:19:43,180 --> 00:19:44,940 +to go do that. + +452 +00:19:44,940 --> 00:19:46,640 +But you have to be a little careful here + +453 +00:19:46,640 --> 00:19:49,740 +because URLSession also takes an argument + +454 +00:19:49,740 --> 00:19:52,200 +which is a closure you give it + +455 +00:19:52,200 --> 00:19:54,910 +to execute when the image comes back. + +456 +00:19:54,910 --> 00:19:58,820 +That closure is also gonna +be executed by URLSession + +457 +00:19:58,820 --> 00:20:00,830 +on this Dispatch global queue. + +458 +00:20:00,830 --> 00:20:02,730 +So we can't do UI in there. + +459 +00:20:02,730 --> 00:20:05,080 +So whenever you're using +something like URLSession + +460 +00:20:05,080 --> 00:20:07,777 +you give the closure that +says, "Hey, go fetch this + +461 +00:20:07,777 --> 00:20:09,850 +"and when you're done, call this closure," + +462 +00:20:09,850 --> 00:20:12,356 +that closure is almost +certainly gonna be doing + +463 +00:20:12,356 --> 00:20:13,189 +DispatchQueue.main.async +inside of it to dispatch + +464 +00:20:16,278 --> 00:20:19,340 +and go back to the main +queue to put the UI result + +465 +00:20:20,470 --> 00:20:23,170 +of whatever was fetched by the URLSession. + +466 +00:20:24,418 --> 00:20:26,520 +Now again today, I want +you to understand GCD. + +467 +00:20:26,520 --> 00:20:29,720 +So that's why we're gonna +do the DispatchQueue global + +468 +00:20:29,720 --> 00:20:30,897 +ourselves and then we're gonna do + +469 +00:20:30,897 --> 00:20:33,360 +a DispatchQueue.main.async ourselves. + +470 +00:20:33,360 --> 00:20:35,730 +But in the real world, if +I was fetching an image + +471 +00:20:35,730 --> 00:20:38,630 +which is what we're doing in +our demo, I'd use URLSession. + +472 +00:20:39,570 --> 00:20:41,910 +All right, so let's get +to that demo right away. + +473 +00:20:41,910 --> 00:20:43,740 +I already talked about +what we're gonna be doing, + +474 +00:20:43,740 --> 00:20:44,823 +so let's do it! + +475 +00:20:46,390 --> 00:20:49,240 +This demo is a pretty big one. + +476 +00:20:49,240 --> 00:20:52,760 +We are going to do a whole +nother app from scratch. + +477 +00:20:52,760 --> 00:20:55,650 +That way you can compare and +contrast what you saw us do + +478 +00:20:55,650 --> 00:20:57,927 +in Memorize versus a +completely different app. + +479 +00:20:57,927 --> 00:21:00,940 +And then hopefully all the +things you did in Memorize + +480 +00:21:00,940 --> 00:21:03,900 +won't seem so, you +know, Memorize specific. + +481 +00:21:03,900 --> 00:21:06,363 +You'll see which ones of +them are just general things + +482 +00:21:06,363 --> 00:21:10,900 +that we're doing in every app +versus those specific things. + +483 +00:21:10,900 --> 00:21:13,530 +Let me show you what this +app is going to look like + +484 +00:21:13,530 --> 00:21:16,110 +before we get started here. + +485 +00:21:16,110 --> 00:21:19,630 +It's called EmojiArt and it lets us build + +486 +00:21:19,630 --> 00:21:23,200 +some sort of art here +out of emojis, of course, + +487 +00:21:23,200 --> 00:21:25,190 +'cause we love emojis. + +488 +00:21:25,190 --> 00:21:27,630 +And across the top you can +see we have some emojis + +489 +00:21:27,630 --> 00:21:29,280 +to choose from to build out of + +490 +00:21:29,280 --> 00:21:32,160 +and we can even choose +different kinds of emojis, + +491 +00:21:32,160 --> 00:21:34,920 +activities, animals, whatever. + +492 +00:21:34,920 --> 00:21:37,520 +These lists of emojis +are editable by the user. + +493 +00:21:37,520 --> 00:21:39,830 +If they click on here, they can actually + +494 +00:21:39,830 --> 00:21:42,630 +remove emojis from there +or even click on here + +495 +00:21:42,630 --> 00:21:45,830 +and go to the emoji keyboard +and add more emojis, + +496 +00:21:45,830 --> 00:21:50,200 +maybe add another face +in here or whatever. + +497 +00:21:50,200 --> 00:21:53,240 +And you use the emojis to build your art + +498 +00:21:53,240 --> 00:21:55,580 +but of course it's nice +to have a good background + +499 +00:21:55,580 --> 00:21:57,340 +so I've gone over here to Google. + +500 +00:21:57,340 --> 00:22:02,280 +By the way, this right +here is the iPad multi-app + +501 +00:22:02,280 --> 00:22:05,480 +user interface here where I've +got my EmojiArt on the left + +502 +00:22:05,480 --> 00:22:07,410 +and I've got Safari on the right. + +503 +00:22:07,410 --> 00:22:10,220 +And I can drag Safari +completely away if I want, + +504 +00:22:10,220 --> 00:22:12,950 +just leaving my EmojiArt or go down here + +505 +00:22:12,950 --> 00:22:16,650 +and grab Safari and drag it back out again + +506 +00:22:16,650 --> 00:22:19,783 +and then resize it to +whatever size that I want. + +507 +00:22:20,670 --> 00:22:23,090 +I'm going to choose my background here + +508 +00:22:23,090 --> 00:22:24,993 +by using drag and drop. + +509 +00:22:25,920 --> 00:22:28,190 +Here I have searched for +my favorite thing here, + +510 +00:22:28,190 --> 00:22:31,230 +countryside cartoons, and +I'm just looking around here + +511 +00:22:31,230 --> 00:22:34,130 +for all the countryside +cartoons on the internet. + +512 +00:22:34,130 --> 00:22:37,370 +And I'm just gonna pick +one here and lift it up + +513 +00:22:37,370 --> 00:22:38,870 +and you see when I drag it over, + +514 +00:22:38,870 --> 00:22:41,010 +it gets that little green +plus sign in the corner. + +515 +00:22:41,010 --> 00:22:45,090 +And if I drop, hmm, it +adds it as the background. + +516 +00:22:45,090 --> 00:22:47,890 +We're gonna make it so +you can zoom in here + +517 +00:22:47,890 --> 00:22:51,230 +or we could pan around a little bit. + +518 +00:22:51,230 --> 00:22:53,160 +Then we can add our emojis. + +519 +00:22:53,160 --> 00:22:57,590 +So let's see, let's see if we +can find, here's a bicyclist. + +520 +00:22:57,590 --> 00:23:00,960 +So we'll just pick up +Mr. bicyclist right here, + +521 +00:23:00,960 --> 00:23:02,730 +put him on the road. + +522 +00:23:02,730 --> 00:23:04,880 +And he's a little small, +so I'm gonna select him + +523 +00:23:04,880 --> 00:23:06,533 +and then make him bigger. + +524 +00:23:08,633 --> 00:23:10,240 +Then of course we'd like +some nature as well. + +525 +00:23:10,240 --> 00:23:11,690 +Let's go find some animals. + +526 +00:23:11,690 --> 00:23:16,690 +Oh, a bee, one of my favorite +things in nature is a bee. + +527 +00:23:16,830 --> 00:23:19,360 +Where would we be without bees? + +528 +00:23:19,360 --> 00:23:21,760 +And maybe we'll add +some perspective to this + +529 +00:23:21,760 --> 00:23:24,810 +by having some of the bees +seem to be closer to us + +530 +00:23:24,810 --> 00:23:27,463 +and some of the bees farther away. + +531 +00:23:29,870 --> 00:23:32,180 +So our goal is to build this app. + +532 +00:23:32,180 --> 00:23:34,110 +Now today, all we're going to do + +533 +00:23:34,110 --> 00:23:36,120 +is put this little thing up here. + +534 +00:23:36,120 --> 00:23:37,300 +We're not gonna have a chooser + +535 +00:23:37,300 --> 00:23:38,820 +that lets us choose different kinds, + +536 +00:23:38,820 --> 00:23:42,440 +we're just gonna have +one row of emoji up here. + +537 +00:23:42,440 --> 00:23:44,420 +And we also want to be +able to drag and drop + +538 +00:23:44,420 --> 00:23:46,830 +to do our background, and +we also want to be able + +539 +00:23:46,830 --> 00:23:50,360 +to pick up these emojis +and drop them in there. + +540 +00:23:50,360 --> 00:23:52,810 +Then your homework for +next week is going to be + +541 +00:23:52,810 --> 00:23:56,550 +to be able to select them +and then resize these emojis + +542 +00:23:56,550 --> 00:23:59,160 +or to move them around. + +543 +00:23:59,160 --> 00:24:02,040 +And then next week, we're also going + +544 +00:24:02,040 --> 00:24:05,133 +to add this little chooser +up here and make it + +545 +00:24:05,133 --> 00:24:07,410 +so that these documents persist + +546 +00:24:07,410 --> 00:24:09,920 +'cause right now, if I quit +this app and went back in, + +547 +00:24:09,920 --> 00:24:11,010 +I'd lose my documents. + +548 +00:24:11,010 --> 00:24:14,110 +So we obviously want to +be able to save documents. + +549 +00:24:14,110 --> 00:24:16,620 +And so we got a lot of +work to do with this app, + +550 +00:24:16,620 --> 00:24:19,643 +but let's get started today +with the basics of it. + +551 +00:24:20,500 --> 00:24:24,960 +So this is a completely +brand new project, of course. + +552 +00:24:24,960 --> 00:24:26,860 +Now you don't have to follow along, + +553 +00:24:26,860 --> 00:24:29,040 +you won't be asked to +do that in your homework + +554 +00:24:29,040 --> 00:24:30,450 +like you were the first two weeks. + +555 +00:24:30,450 --> 00:24:34,180 +But again, it's always +recommended as a learning exercise + +556 +00:24:34,180 --> 00:24:36,370 +to follow along. + +557 +00:24:36,370 --> 00:24:40,210 +So let's get started here +by clicking new project. + +558 +00:24:40,210 --> 00:24:43,180 +We always pick Single +View App in this class. + +559 +00:24:43,180 --> 00:24:47,020 +I'm gonna call this thing +EmojiArt, all right. + +560 +00:24:47,020 --> 00:24:49,950 +Everything else the same +as we had for Memorize. + +561 +00:24:49,950 --> 00:24:52,330 +And I'm gonna put it in +Developer right here, + +562 +00:24:52,330 --> 00:24:54,200 +same place as I'm putting my Memorize. + +563 +00:24:55,761 --> 00:24:58,260 +And here it is, let's +go make a lot of space + +564 +00:24:58,260 --> 00:25:00,220 +so that we can see our code very clearly. + +565 +00:25:00,220 --> 00:25:02,453 +We'll even make that a little small there. + +566 +00:25:03,536 --> 00:25:04,369 +Now let's dive right in. + +567 +00:25:04,369 --> 00:25:07,490 +You already know the basics +of how to do things here + +568 +00:25:07,490 --> 00:25:10,940 +so let's start by making our ViewModel. + +569 +00:25:10,940 --> 00:25:14,143 +So I'm just gonna go up +here, File, New, File. + +570 +00:25:15,050 --> 00:25:17,790 +And it's a Swift file, +right, part of the UI + +571 +00:25:17,790 --> 00:25:19,180 +but not a View itself. + +572 +00:25:19,180 --> 00:25:21,771 +Oh, let's make sure we +put it in the right place. + +573 +00:25:21,771 --> 00:25:25,310 +And I'm gonna call my +ViewModel here EmojiArtDocument + +574 +00:25:25,310 --> 00:25:28,480 +because my ViewModel's gonna +represent one document, + +575 +00:25:28,480 --> 00:25:29,530 +one EmojiArtDocument. + +576 +00:25:30,450 --> 00:25:33,760 +And you could imagine some day having a UI + +577 +00:25:33,760 --> 00:25:36,760 +in my EmojiArt that would let +me open different documents + +578 +00:25:36,760 --> 00:25:40,033 +and each one would be represented +with its own ViewModel. + +579 +00:25:41,230 --> 00:25:42,900 +ViewModels of course are UI + +580 +00:25:42,900 --> 00:25:46,170 +so we're gonna important SwiftUI +and they're also classes, + +581 +00:25:46,170 --> 00:25:49,700 +so we're gonna have this +EmojiArtDocument be a class + +582 +00:25:49,700 --> 00:25:54,700 +and we always do ObservableObject +for our ViewModels + +583 +00:25:54,950 --> 00:25:57,880 +because they're the thing +that manage this reactiveness + +584 +00:25:57,880 --> 00:26:00,330 +between things change in the Model + +585 +00:26:00,330 --> 00:26:03,230 +and we see them in the UI. + +586 +00:26:03,230 --> 00:26:06,620 +Now that we have a ViewModel, +let's go back to our View + +587 +00:26:06,620 --> 00:26:08,860 +which is this ContentView right here + +588 +00:26:08,860 --> 00:26:11,160 +with this default ContentView business. + +589 +00:26:11,160 --> 00:26:13,040 +And I'm gonna put my ViewModel here + +590 +00:26:13,040 --> 00:26:16,940 +so I'm gonna have ObservedObject var. + +591 +00:26:16,940 --> 00:26:18,620 +Now I'm not gonna call it viewModel. + +592 +00:26:18,620 --> 00:26:19,670 +That's what we called it before. + +593 +00:26:19,670 --> 00:26:20,510 +I'm gonna call it something + +594 +00:26:20,510 --> 00:26:22,660 +we would actually call it. (chuckles) + +595 +00:26:22,660 --> 00:26:25,770 +In this case document, and +that's an EmojiArtDocument. + +596 +00:26:26,960 --> 00:26:30,038 +We're not gonna do preview +right off the bat here. + +597 +00:26:30,038 --> 00:26:32,820 +Our EmojiArt View is pretty +much all about the things + +598 +00:26:32,820 --> 00:26:33,653 +that are dragged into it, + +599 +00:26:33,653 --> 00:26:36,450 +and of course in the preview +window we can't drag it + +600 +00:26:36,450 --> 00:26:38,730 +in there but eventually +we probably would want + +601 +00:26:38,730 --> 00:26:42,840 +to put that preview back and +have maybe some test data + +602 +00:26:42,840 --> 00:26:44,998 +of some emojis in a background + +603 +00:26:44,998 --> 00:26:47,420 +so that we could see to make +sure that thing looks good. + +604 +00:26:47,420 --> 00:26:48,793 +But for general purposes here, + +605 +00:26:48,793 --> 00:26:51,003 +we'll just turn that off for now. + +606 +00:26:52,090 --> 00:26:54,930 +And I don't like this name +ContentView right here. + +607 +00:26:54,930 --> 00:26:57,620 +That's bad, so let's do the +same thing we did before. + +608 +00:26:57,620 --> 00:27:00,493 +Command click on this and say Rename. + +609 +00:27:01,330 --> 00:27:03,790 +And now it's kind of +searching for all the places, + +610 +00:27:03,790 --> 00:27:05,930 +you can see it here, that this appears. + +611 +00:27:05,930 --> 00:27:06,850 +And so I'm gonna rename this + +612 +00:27:06,850 --> 00:27:08,243 +to be EmojiArtDocumentView. + +613 +00:27:10,511 --> 00:27:12,756 +It's gonna be a View +that shows a document. + +614 +00:27:12,756 --> 00:27:14,560 +And we can see, uh, it's +not going to rename that. + +615 +00:27:14,560 --> 00:27:17,430 +Okay, we'll have to do that ourselves. + +616 +00:27:17,430 --> 00:27:18,393 +It's up here. + +617 +00:27:20,890 --> 00:27:22,520 +And of course, we got to change, + +618 +00:27:22,520 --> 00:27:24,210 +look at the places where this is called + +619 +00:27:24,210 --> 00:27:27,470 +and make sure we create a +ViewModel for these things + +620 +00:27:27,470 --> 00:27:30,330 +and we know that's over +here in our SceneDelegate, + +621 +00:27:30,330 --> 00:27:32,293 +contentView equals EmojiArtDocumentView. + +622 +00:27:33,235 --> 00:27:35,020 +And we'll have the document be for now + +623 +00:27:35,020 --> 00:27:39,450 +just a default EmojiArtDocument, +an empty document. + +624 +00:27:39,450 --> 00:27:40,797 +Doesn't have anything in it. + +625 +00:27:40,797 --> 00:27:43,730 +And it's okay for us to do this initialize + +626 +00:27:43,730 --> 00:27:46,650 +with no arguments 'cause if we +look at our EmojiArtDocument + +627 +00:27:46,650 --> 00:27:50,200 +it has no uninitialized +variables, so it's perfectly fine + +628 +00:27:50,200 --> 00:27:52,310 +to do init that way. + +629 +00:27:52,310 --> 00:27:56,900 +All right, so let's start +building our UI right off the bat + +630 +00:27:56,900 --> 00:28:01,160 +and our UI, if you recall, +has this emoji at the top. + +631 +00:28:01,160 --> 00:28:03,890 +So let's try and build this little nice + +632 +00:28:03,890 --> 00:28:08,170 +scrollable list of emoji +there, see if we can do that. + +633 +00:28:08,170 --> 00:28:11,060 +Now that scrollable list of +emoji, that palette at the top, + +634 +00:28:11,060 --> 00:28:12,660 +that's shared by all documents. + +635 +00:28:12,660 --> 00:28:17,030 +So that does not want to +be a var in an instance + +636 +00:28:17,030 --> 00:28:19,030 +of the document, 'cause +remember an instance + +637 +00:28:19,030 --> 00:28:21,370 +of this ViewModel represents one document. + +638 +00:28:21,370 --> 00:28:23,997 +That wants to be a static var. + +639 +00:28:23,997 --> 00:28:27,040 +And in fact, for now we're +gonna make him static let, + +640 +00:28:27,040 --> 00:28:29,900 +this palette of emoji, + +641 +00:28:29,900 --> 00:28:34,030 +and well, we'll just put some +random things in here for now. + +642 +00:28:34,030 --> 00:28:35,400 +We know how to add emojis. + +643 +00:28:35,400 --> 00:28:39,210 +We'll go here, sure, put a star in there, + +644 +00:28:39,210 --> 00:28:42,200 +some clouds, what else we got down here? + +645 +00:28:42,200 --> 00:28:46,800 +An apple, yeah, maybe a earth. + +646 +00:28:46,800 --> 00:28:49,123 +And then what else we got, a pretzel, + +647 +00:28:50,330 --> 00:28:52,350 +yeah, and I don't wanna make you hungry + +648 +00:28:52,350 --> 00:28:54,070 +so I won't put any food in there. + +649 +00:28:54,070 --> 00:28:57,050 +But maybe like a baseball, +that kinda thing. + +650 +00:28:57,050 --> 00:29:00,410 +All right, so this is just +gonna be our default palette. + +651 +00:29:00,410 --> 00:29:04,210 +Eventually this is going to +become an Array of palettes + +652 +00:29:04,210 --> 00:29:07,760 +so that we can have that +nice chooser right here + +653 +00:29:07,760 --> 00:29:11,000 +where we can choose +between these palettes. + +654 +00:29:11,000 --> 00:29:13,940 +But for now, we're not, we +don't have that feature. + +655 +00:29:13,940 --> 00:29:15,500 +And so now that we have this palette, + +656 +00:29:15,500 --> 00:29:17,530 +let's just make our document View + +657 +00:29:17,530 --> 00:29:18,950 +instead of saying "Hello, World!" + +658 +00:29:18,950 --> 00:29:21,290 +let's have it display that. + +659 +00:29:21,290 --> 00:29:22,960 +Now this should be something you can + +660 +00:29:22,960 --> 00:29:25,070 +kind of instantly imagine +how we're gonna do. + +661 +00:29:25,070 --> 00:29:27,973 +We're just gonna make +an HStack of ForEach. + +662 +00:29:29,150 --> 00:29:32,450 +And the ForEach is going to +be those EmojiArtDocument, + +663 +00:29:32,450 --> 00:29:34,310 +that static palette. + +664 +00:29:34,310 --> 00:29:36,840 +And then for each of the emojis in there + +665 +00:29:36,840 --> 00:29:39,730 +we want to just put a Text of the emoji. + +666 +00:29:39,730 --> 00:29:43,860 +Now this doesn't quite work +because this is a String + +667 +00:29:43,860 --> 00:29:47,610 +and ForEach remember wants an Array, + +668 +00:29:47,610 --> 00:29:50,090 +either a range of Ints +or it wants an Array + +669 +00:29:50,090 --> 00:29:51,850 +of Identifiable things. + +670 +00:29:51,850 --> 00:29:53,520 +And so a String is not an Array. + +671 +00:29:53,520 --> 00:29:57,260 +It's close, but there's a +great little function on String + +672 +00:29:57,260 --> 00:30:00,430 +called map which will +turn it into an Array + +673 +00:30:00,430 --> 00:30:01,770 +by calling a function, + +674 +00:30:01,770 --> 00:30:04,933 +which we're going to +call String zero here. + +675 +00:30:05,810 --> 00:30:08,700 +And this function takes each +character in the String, + +676 +00:30:08,700 --> 00:30:11,790 +so $0 is a character in the String + +677 +00:30:11,790 --> 00:30:14,757 +and it just, we're gonna +apply this function to it. + +678 +00:30:14,757 --> 00:30:16,380 +But we're just gonna +turn it into a String. + +679 +00:30:16,380 --> 00:30:18,780 +So String knows how to +take a single character + +680 +00:30:18,780 --> 00:30:19,967 +and turn it into a String. + +681 +00:30:19,967 --> 00:30:23,610 +And so now we have ForEach +on an Array of Strings. + +682 +00:30:23,610 --> 00:30:25,730 +This map returns an Array of Strings. + +683 +00:30:25,730 --> 00:30:27,540 +So that's cool, and +that means this emoji's + +684 +00:30:27,540 --> 00:30:28,690 +gonna be a String. + +685 +00:30:28,690 --> 00:30:29,600 +But it's still not working. + +686 +00:30:29,600 --> 00:30:33,450 +We're getting the dreaded +Oh, expected range of Int. + +687 +00:30:33,450 --> 00:30:35,010 +And we know why that is. + +688 +00:30:35,010 --> 00:30:38,670 +ForEach takes an Array of Identifiable + +689 +00:30:38,670 --> 00:30:42,360 +and Strings are not Identifiable. + +690 +00:30:42,360 --> 00:30:46,180 +Now it's interesting, we could +put an extension on String + +691 +00:30:46,180 --> 00:30:48,880 +to make it Identifiable, like this. + +692 +00:30:48,880 --> 00:30:51,080 +Just by doing var id. + +693 +00:30:51,080 --> 00:30:53,050 +And I have a cool way to do that. + +694 +00:30:53,050 --> 00:30:55,280 +I'm gonna have the id be a String. + +695 +00:30:55,280 --> 00:30:59,260 +I'm just gonna return +myself, okay I'm a String. + +696 +00:30:59,260 --> 00:31:01,170 +Strings are equatable. + +697 +00:31:01,170 --> 00:31:04,740 +By the way, this don't care +for the id and Identifiable, + +698 +00:31:04,740 --> 00:31:06,660 +it's not a complete don't care. + +699 +00:31:06,660 --> 00:31:09,918 +Obviously this id has to be Equatable. + +700 +00:31:09,918 --> 00:31:11,410 +You have to be able to say == on it. + +701 +00:31:11,410 --> 00:31:13,770 +Otherwise I can't tell if +two Identifiable things + +702 +00:31:13,770 --> 00:31:14,700 +are the same. + +703 +00:31:14,700 --> 00:31:17,000 +But a String, you can certainly do == on + +704 +00:31:17,000 --> 00:31:18,200 +so this is fine. + +705 +00:31:18,200 --> 00:31:19,677 +But what's this error that I'm getting. + +706 +00:31:19,677 --> 00:31:22,817 +"Property id must be declared public + +707 +00:31:22,817 --> 00:31:24,237 +"because it matches a requirement + +708 +00:31:24,237 --> 00:31:27,130 +"in a public protocol 'Identifiable.'" + +709 +00:31:27,130 --> 00:31:29,690 +Well, Identifiable is +indeed a public protocol + +710 +00:31:29,690 --> 00:31:31,780 +and String is a public class. + +711 +00:31:31,780 --> 00:31:35,320 +So that makes us have to +mark this also as public. + +712 +00:31:35,320 --> 00:31:36,610 +Now what does public mean? + +713 +00:31:36,610 --> 00:31:39,430 +We have not seen the +access control public. + +714 +00:31:39,430 --> 00:31:43,700 +We saw private, and private +set, but we haven't seen public. + +715 +00:31:43,700 --> 00:31:48,140 +Public means non-private in a library. + +716 +00:31:48,140 --> 00:31:51,800 +Identifiable and String +are clearly in the SwiftUI + +717 +00:31:51,800 --> 00:31:53,910 +imported library right here. + +718 +00:31:53,910 --> 00:31:56,810 +And so they have to mark +things that they want people + +719 +00:31:56,810 --> 00:32:01,100 +outside the library to actually +be able to see with public. + +720 +00:32:01,100 --> 00:32:02,940 +Now you'd not gonna be doing +libraries in this class + +721 +00:32:02,940 --> 00:32:05,060 +so you're never gonna +mark anything public. + +722 +00:32:05,060 --> 00:32:06,940 +But if one day you do work on a library, + +723 +00:32:06,940 --> 00:32:09,513 +you'll know what public +is all about there. + +724 +00:32:10,780 --> 00:32:13,440 +Now this does work, you +see, no errors, right? + +725 +00:32:13,440 --> 00:32:15,290 +This is now an Array of Identifiables + +726 +00:32:16,440 --> 00:32:18,270 +because Strings are Identifiables. + +727 +00:32:18,270 --> 00:32:20,410 +But this is also wrong, okay. + +728 +00:32:20,410 --> 00:32:21,480 +We really wouldn't (chuckles) + +729 +00:32:21,480 --> 00:32:25,220 +want to make Strings Identifiable +throughout our entire app. + +730 +00:32:25,220 --> 00:32:26,760 +That's really, we only want them + +731 +00:32:26,760 --> 00:32:29,290 +to be Identifiable right here. + +732 +00:32:29,290 --> 00:32:31,370 +And ForEach understands +that you're sometimes + +733 +00:32:31,370 --> 00:32:34,170 +gonna pass an Array of +something that you don't, + +734 +00:32:34,170 --> 00:32:37,950 +you can't make it conform to Identifiable. + +735 +00:32:37,950 --> 00:32:39,960 +So it has a nice little extra argument + +736 +00:32:39,960 --> 00:32:42,130 +you could specify called id. + +737 +00:32:42,130 --> 00:32:47,130 +Now id lets you specify +which var on these things + +738 +00:32:48,240 --> 00:32:50,860 +to use to uniquely identify it. + +739 +00:32:50,860 --> 00:32:53,940 +So it's essentially like +use this var as the id + +740 +00:32:53,940 --> 00:32:55,850 +as if this thing were Identifiable, + +741 +00:32:55,850 --> 00:32:57,220 +which is really really convenient. + +742 +00:32:57,220 --> 00:33:01,413 +Now the var that I'm gonna +use in String is .self. + +743 +00:33:02,290 --> 00:33:05,950 +Okay, (chuckles) so every +object essentially has a var + +744 +00:33:05,950 --> 00:33:09,100 +you can't see called +self and that is itself. + +745 +00:33:09,100 --> 00:33:12,140 +So that's a great identifier for a String. + +746 +00:33:12,140 --> 00:33:16,640 +But what is this syntax +right here, \.self? + +747 +00:33:16,640 --> 00:33:19,550 +This is called a key path in Swift. + +748 +00:33:19,550 --> 00:33:22,630 +And a key path is just a +really cool simple syntax + +749 +00:33:22,630 --> 00:33:27,130 +to be able to specify a +var on another object. + +750 +00:33:27,130 --> 00:33:29,980 +So here, this is backslash +means this is a key path + +751 +00:33:29,980 --> 00:33:33,453 +and dot means on this thing right here, + +752 +00:33:33,453 --> 00:33:36,620 +this class of things, String, self. + +753 +00:33:36,620 --> 00:33:38,470 +And I could press any, you know, any var. + +754 +00:33:38,470 --> 00:33:41,010 +I could even say like this, foo.bar + +755 +00:33:41,010 --> 00:33:44,260 +and call a var to return +something, then call a var on that. + +756 +00:33:44,260 --> 00:33:46,050 +It's a pretty flexible little system, + +757 +00:33:46,050 --> 00:33:48,700 +this little key path oriented stuff. + +758 +00:33:48,700 --> 00:33:51,900 +But you can see that fixes +everything right here. + +759 +00:33:51,900 --> 00:33:54,503 +So let's run it and see what we got here. + +760 +00:33:55,740 --> 00:33:57,400 +And let's not run on an iPhone. + +761 +00:33:57,400 --> 00:34:00,120 +So this app that we're doing right here + +762 +00:34:00,120 --> 00:34:02,280 +is going to be an iPad app. + +763 +00:34:02,280 --> 00:34:05,270 +I'm gonna make it primarily for the iPad. + +764 +00:34:05,270 --> 00:34:08,910 +We're gonna find that because +of the power of SwiftUI, + +765 +00:34:08,910 --> 00:34:10,770 +it's going to work (chuckles) +quite well on the iPhone + +766 +00:34:10,770 --> 00:34:13,570 +as well but we're gonna +develop it on the iPad first. + +767 +00:34:13,570 --> 00:34:16,580 +We drag and drop and all these +things we want over here. + +768 +00:34:16,580 --> 00:34:19,180 +So there it is, yeah +this shows Safari here + +769 +00:34:19,180 --> 00:34:21,770 +and now we're running our +version of EmojiArt over here + +770 +00:34:21,770 --> 00:34:25,030 +so we lost all the stuff that +I was showing you before. + +771 +00:34:25,030 --> 00:34:27,010 +But here they are, look +at that, those are emojis. + +772 +00:34:27,010 --> 00:34:29,150 +Now, well our emojis have a little bit + +773 +00:34:29,150 --> 00:34:30,210 +of some problems here. + +774 +00:34:30,210 --> 00:34:32,360 +One, they're really small and we want 'em + +775 +00:34:32,360 --> 00:34:35,550 +to be scrollable, so let's +go fix some of these things. + +776 +00:34:35,550 --> 00:34:37,520 +The smallness, we know how to fix that. + +777 +00:34:37,520 --> 00:34:41,410 +We're just gonna say .font +and we'll use a system font + +778 +00:34:41,410 --> 00:34:45,140 +of size and I'm gonna be +a good programmer here + +779 +00:34:45,140 --> 00:34:48,330 +and actually make a little let down here, + +780 +00:34:48,330 --> 00:34:53,330 +probably a private let +called my defaultEmojiSize. + +781 +00:34:53,940 --> 00:34:55,317 +It's gonna be CGFloat. + +782 +00:34:55,317 --> 00:34:57,367 +I'm gonna say 40, I think I tried that out + +783 +00:34:57,367 --> 00:34:59,100 +and it seemed pretty good. + +784 +00:34:59,100 --> 00:35:02,029 +So let's say +self.defaultEmojiSize right here. + +785 +00:35:02,029 --> 00:35:03,029 +That'll make it big. + +786 +00:35:04,041 --> 00:35:05,303 +Let's see what that looks like. + +787 +00:35:07,801 --> 00:35:08,870 +Yeah, okay, definitely much better. + +788 +00:35:08,870 --> 00:35:10,870 +That's closer to what +we were having before. + +789 +00:35:10,870 --> 00:35:12,020 +What about the scrollability? + +790 +00:35:12,020 --> 00:35:14,360 +I'm dragging on this, it's not scrolling + +791 +00:35:14,360 --> 00:35:17,470 +back and forth here, +that's super easy in Swift. + +792 +00:35:17,470 --> 00:35:19,820 +So this is so easy, I was +thinking of having slides + +793 +00:35:19,820 --> 00:35:21,510 +on this (chuckles) and +how to do ScrollViews + +794 +00:35:21,510 --> 00:35:24,970 +but it's so easy, it's +really hardly even worth + +795 +00:35:24,970 --> 00:35:26,270 +having a slide over. + +796 +00:35:26,270 --> 00:35:28,710 +You just put it in a +ScrollView and a ScrollView + +797 +00:35:28,710 --> 00:35:31,140 +will let you specify whether +it scrolls horizontally + +798 +00:35:31,140 --> 00:35:32,670 +or vertically or both. + +799 +00:35:32,670 --> 00:35:36,460 +So our ScrollView obviously +only scrolls horizontally. + +800 +00:35:36,460 --> 00:35:39,320 +We just wrap this in there +and that's all we have to do. + +801 +00:35:39,320 --> 00:35:42,410 +Now this HStack that we had +is going to be scrollable. + +802 +00:35:42,410 --> 00:35:45,280 +You see, I can scroll it around. + +803 +00:35:45,280 --> 00:35:47,560 +And one thing I don't +like, it's kinda close + +804 +00:35:47,560 --> 00:35:48,610 +to the edge right there. + +805 +00:35:48,610 --> 00:35:51,490 +I want a little bit of +room and we know how to do, + +806 +00:35:51,490 --> 00:35:53,360 +add a little bit of room to things. + +807 +00:35:53,360 --> 00:35:56,580 +So let's take this ScrollView +and add a little padding. + +808 +00:35:56,580 --> 00:35:59,510 +And I'm only gonna do +padding horizontally. + +809 +00:35:59,510 --> 00:36:01,137 +You've probably gathered by now + +810 +00:36:01,137 --> 00:36:03,630 +how the padding has a lot +of different arguments. + +811 +00:36:03,630 --> 00:36:06,530 +You can specify exact +paddings on just some edges + +812 +00:36:06,530 --> 00:36:08,300 +or default paddings or whatever. + +813 +00:36:08,300 --> 00:36:09,950 +This is gonna give me the default padding + +814 +00:36:09,950 --> 00:36:12,063 +but only on the left and right. + +815 +00:36:13,322 --> 00:36:16,480 +And I probably want the, +vertically I want this thing + +816 +00:36:17,540 --> 00:36:19,520 +to use as little space as possible. + +817 +00:36:19,520 --> 00:36:20,610 +So I don't really want padding there + +818 +00:36:20,610 --> 00:36:23,160 +'cause I want my document +to be as big as possible. + +819 +00:36:24,130 --> 00:36:27,000 +Speaking of my document, +let's get my document on there + +820 +00:36:27,000 --> 00:36:28,610 +and have this push up to the top + +821 +00:36:28,610 --> 00:36:32,053 +and my document use all the +rest of the space over there. + +822 +00:36:33,090 --> 00:36:36,490 +It's until we write the code +that actually does a document + +823 +00:36:36,490 --> 00:36:38,670 +that can have a background +and have all those emojis + +824 +00:36:38,670 --> 00:36:42,220 +on there, I'm just going +to use a yellow rectangle + +825 +00:36:42,220 --> 00:36:43,950 +to be my document. + +826 +00:36:43,950 --> 00:36:47,660 +So I'm gonna put it in a VStack +here with this ScrollView + +827 +00:36:47,660 --> 00:36:50,370 +that we just built for the emoji, + +828 +00:36:50,370 --> 00:36:55,130 +and a rectangle that is +foregroundColor yellow. + +829 +00:37:00,660 --> 00:37:02,500 +And well, that's pretty +darn close (chuckles) + +830 +00:37:02,500 --> 00:37:04,430 +to already looking exactly what I want. + +831 +00:37:04,430 --> 00:37:07,130 +Okay, I've got my scrollable +list of emoji up here. + +832 +00:37:07,130 --> 00:37:09,040 +We could have any amount +of emoji we wanted. + +833 +00:37:09,040 --> 00:37:10,687 +And here's my document. + +834 +00:37:10,687 --> 00:37:14,330 +The only thing is I really +don't want this white line + +835 +00:37:14,330 --> 00:37:17,890 +down here, why is this not +yellow all the way to the bottom? + +836 +00:37:17,890 --> 00:37:19,590 +And it's not yellow all +the way to the bottom + +837 +00:37:19,590 --> 00:37:23,110 +because it's only drawing +this yellow in the safe area, + +838 +00:37:23,110 --> 00:37:26,060 +what's called the safe area of this View. + +839 +00:37:26,060 --> 00:37:29,220 +And it considers this little +area down here not safe + +840 +00:37:29,220 --> 00:37:30,480 +because it's got this little, + +841 +00:37:30,480 --> 00:37:33,880 +you see this little bar right here? + +842 +00:37:33,880 --> 00:37:36,120 +That's the bar that you +use if you want to switch + +843 +00:37:36,120 --> 00:37:38,600 +to other apps in the iPad. + +844 +00:37:38,600 --> 00:37:41,150 +And so it considers that an adornment + +845 +00:37:41,150 --> 00:37:42,970 +that's always on the screen. + +846 +00:37:42,970 --> 00:37:45,200 +By default, it doesn't draw over that + +847 +00:37:45,200 --> 00:37:46,690 +in case there's something critical + +848 +00:37:46,690 --> 00:37:48,620 +that your app is drawing behind it. + +849 +00:37:48,620 --> 00:37:51,010 +But our app, we're gonna be +able to zoom and pan around + +850 +00:37:51,010 --> 00:37:52,770 +so if there was some +critical emoji (chuckles) + +851 +00:37:52,770 --> 00:37:54,790 +underneath this bar, we just move it, + +852 +00:37:54,790 --> 00:37:56,780 +move our document out +of the way a little bit. + +853 +00:37:56,780 --> 00:37:59,700 +So we do want to move to +the edges right there. + +854 +00:37:59,700 --> 00:38:03,010 +And in general in iOS +when we are building apps, + +855 +00:38:03,010 --> 00:38:04,560 +content is king. + +856 +00:38:04,560 --> 00:38:08,650 +We want to use as much space +as possible for our content + +857 +00:38:08,650 --> 00:38:11,190 +and as little space as +possible for adornments, okay, + +858 +00:38:11,190 --> 00:38:13,030 +these little things like that + +859 +00:38:13,030 --> 00:38:15,350 +or like, or even our emoji here. + +860 +00:38:15,350 --> 00:38:17,270 +We want to try and keep that kinda small + +861 +00:38:17,270 --> 00:38:20,160 +so we have this huge +space for our document. + +862 +00:38:20,160 --> 00:38:22,307 +So how do we tell +SwiftUI, "Yeah, go ahead, + +863 +00:38:22,307 --> 00:38:25,500 +"use these unsafe areas like +this little thing right here." + +864 +00:38:25,500 --> 00:38:29,520 +By the way, the notch on the +iPhone is also an unsafe area. + +865 +00:38:29,520 --> 00:38:32,230 +So if want to use that, +that is no problem. + +866 +00:38:32,230 --> 00:38:34,380 +We're just gonna go to our rectangle here + +867 +00:38:34,380 --> 00:38:37,570 +and say edges ignoring the safe area + +868 +00:38:37,570 --> 00:38:40,890 +are, and I'm gonna do the +horizontal edges left and right + +869 +00:38:40,890 --> 00:38:43,670 +and also the bottom edge. + +870 +00:38:43,670 --> 00:38:47,340 +So I can do multiple areas to ignore here. + +871 +00:38:47,340 --> 00:38:49,263 +So let's see what that looks like. + +872 +00:38:53,684 --> 00:38:54,780 +Whoo-hoo! + +873 +00:38:54,780 --> 00:38:58,010 +We want to make that yellow +rectangle be our document + +874 +00:38:58,010 --> 00:39:00,730 +so we need a Model for that document. + +875 +00:39:00,730 --> 00:39:03,800 +Now our Model for that +document is just going to be + +876 +00:39:03,800 --> 00:39:05,967 +the background and then all the emoji + +877 +00:39:05,967 --> 00:39:07,760 +and where they are and what size they are. + +878 +00:39:07,760 --> 00:39:09,600 +That is, that's the entire Model. + +879 +00:39:09,600 --> 00:39:11,430 +Now don't get confused here + +880 +00:39:11,430 --> 00:39:14,900 +and maybe just because you did +Memorize and you had themes, + +881 +00:39:14,900 --> 00:39:18,290 +you might be a little +wondering what's going on here. + +882 +00:39:18,290 --> 00:39:20,240 +Yes, the Model for an EmojiArtDocument + +883 +00:39:21,330 --> 00:39:25,770 +is representing a visual +thing, the emoji art itself. + +884 +00:39:25,770 --> 00:39:29,080 +But it's not itself a UI element. + +885 +00:39:29,080 --> 00:39:32,780 +It's still a kind of device +independent representation + +886 +00:39:32,780 --> 00:39:35,400 +of an EmojiArtDocument, it's up to some UI + +887 +00:39:35,400 --> 00:39:39,280 +like SwiftUI to turn it into +something that we can draw. + +888 +00:39:39,280 --> 00:39:42,860 +And I'm gonna emphasize this +by making the coordinates + +889 +00:39:42,860 --> 00:39:45,800 +of these emojis and the size be Ints, + +890 +00:39:45,800 --> 00:39:48,320 +and clearly SwiftUI doesn't work in Ints, + +891 +00:39:48,320 --> 00:39:51,460 +it works in CGFloat, right, +floating point numbers. + +892 +00:39:51,460 --> 00:39:54,330 +But I'm gonna make 'em Ints +just so you can be really + +893 +00:39:54,330 --> 00:39:56,240 +seeing the difference between my Model, + +894 +00:39:56,240 --> 00:39:59,300 +which is this device +independent, UI independent + +895 +00:39:59,300 --> 00:40:01,483 +representation of it and my UI. + +896 +00:40:02,860 --> 00:40:04,757 +So let's go create that Model. + +897 +00:40:04,757 --> 00:40:07,350 +We're gonna go File, New up here. + +898 +00:40:07,350 --> 00:40:11,380 +And it is a Model, so it's a Swift file. + +899 +00:40:11,380 --> 00:40:12,560 +It's all in the right places. + +900 +00:40:12,560 --> 00:40:15,110 +I'm gonna call my Model EmojiArt. + +901 +00:40:15,110 --> 00:40:17,980 +That is what my Model is, it's emoji art. + +902 +00:40:17,980 --> 00:40:20,849 +Here it is, I'm not gonna +change to SwiftUI here. + +903 +00:40:20,849 --> 00:40:23,319 +Just going to import Foundation. + +904 +00:40:23,319 --> 00:40:26,490 +It's a simple struct called EmojiArt + +905 +00:40:26,490 --> 00:40:29,660 +and it has this backgroundURL. + +906 +00:40:29,660 --> 00:40:32,454 +I'm gonna store the URL for background. + +907 +00:40:32,454 --> 00:40:36,330 +It's gonna be of type +URL, optional URL though. + +908 +00:40:36,330 --> 00:40:40,070 +This URL is just a Swift library struct + +909 +00:40:40,070 --> 00:40:44,097 +that holds a URL like https://. + +910 +00:40:44,097 --> 00:40:46,067 +That is a URL and it holds it + +911 +00:40:46,067 --> 00:40:49,000 +and it also can hold file URLs in there. + +912 +00:40:49,000 --> 00:40:50,690 +And the reason I'm making this optional + +913 +00:40:50,690 --> 00:40:52,670 +is that our documents obviously start out + +914 +00:40:52,670 --> 00:40:55,570 +with no background and it's actually valid + +915 +00:40:55,570 --> 00:40:57,664 +to have an EmojiArtDocument +with no background. + +916 +00:40:57,664 --> 00:41:00,290 +It would just be probably +white or something. + +917 +00:41:00,290 --> 00:41:02,100 +It wouldn't look that good maybe. + +918 +00:41:02,100 --> 00:41:04,510 +But it's certainly legal, so that's why + +919 +00:41:04,510 --> 00:41:06,450 +I'm gonna make this an optional. + +920 +00:41:06,450 --> 00:41:08,230 +The other thing is the emojis. + +921 +00:41:08,230 --> 00:41:11,990 +So the emojis are just gonna +be some Array of emojis + +922 +00:41:11,990 --> 00:41:15,260 +of some sort, so I'm gonna +have to have a struct Emoji + +923 +00:41:15,260 --> 00:41:17,270 +that represents the emojis. + +924 +00:41:17,270 --> 00:41:18,920 +Just like we had card in Memorize, + +925 +00:41:18,920 --> 00:41:21,600 +here we happen to have +emojis in our EmojiArt. + +926 +00:41:21,600 --> 00:41:23,633 +And what is in an Emoji? + +927 +00:41:23,633 --> 00:41:26,820 +It's obviously the text, +right, the actual emoji + +928 +00:41:26,820 --> 00:41:29,050 +like the smiley face or whatever. + +929 +00:41:29,050 --> 00:41:31,070 +It's got position and I told you + +930 +00:41:31,070 --> 00:41:33,820 +I'm gonna do position using Ints. + +931 +00:41:33,820 --> 00:41:35,500 +Take note here, by the way, + +932 +00:41:35,500 --> 00:41:38,760 +that I'm gonna have the +coordinate system of this X and Y + +933 +00:41:38,760 --> 00:41:42,300 +have (0, 0) right in the +center of my document. + +934 +00:41:42,300 --> 00:41:44,580 +And that's different from +iOS's coordinate system. + +935 +00:41:44,580 --> 00:41:46,830 +You'll remember from when we did our Pie + +936 +00:41:46,830 --> 00:41:47,830 +that that coordinate system + +937 +00:41:47,830 --> 00:41:49,790 +is (0, 0) in the upper left. + +938 +00:41:49,790 --> 00:41:51,750 +And I'm gonna have X and +Y here be in the center. + +939 +00:41:51,750 --> 00:41:54,680 +And note that because +later on when we're working + +940 +00:41:54,680 --> 00:41:56,410 +in our View, we're gonna have to convert + +941 +00:41:56,410 --> 00:41:58,270 +from this coordinate system of our Model + +942 +00:41:58,270 --> 00:42:00,580 +which is, it's (0, 0) is the center, + +943 +00:42:00,580 --> 00:42:04,240 +to our iOS coordinate +system (0, 0) upper left. + +944 +00:42:04,240 --> 00:42:08,320 +So also we go to size, we can +do that with an Int as well. + +945 +00:42:08,320 --> 00:42:10,350 +Notice that I made the text be a let. + +946 +00:42:10,350 --> 00:42:13,360 +Once you create an emoji in +EmojiArt like a smiley face + +947 +00:42:13,360 --> 00:42:16,050 +or a panda or a bicycle +or whatever (chuckles) + +948 +00:42:16,050 --> 00:42:18,110 +it is going to always be that. + +949 +00:42:18,110 --> 00:42:20,941 +We're never gonna allow +you to change that emoji. + +950 +00:42:20,941 --> 00:42:22,010 +And that's just the decision I made + +951 +00:42:22,010 --> 00:42:24,190 +and I make that decision +or I express that decision + +952 +00:42:24,190 --> 00:42:26,163 +by having this be a let. + +953 +00:42:27,050 --> 00:42:29,960 +Now we can already +anticipate that in our UI + +954 +00:42:30,811 --> 00:42:33,087 +this emoji is gonna +want to be Identifiable. + +955 +00:42:33,087 --> 00:42:35,200 +And clearly we're gonna have to ForEach + +956 +00:42:35,200 --> 00:42:38,240 +through our Emojis and +show them all on screen. + +957 +00:42:38,240 --> 00:42:41,190 +So I'm gonna make this Identifiable. + +958 +00:42:41,190 --> 00:42:44,253 +And that requires us to do this var id. + +959 +00:42:45,340 --> 00:42:48,090 +Now what is our id gonna be? + +960 +00:42:48,090 --> 00:42:51,140 +In our Memorize game, we +made it be like pretty much + +961 +00:42:51,140 --> 00:42:53,720 +which pair does like, first +pair it with zero and one, + +962 +00:42:53,720 --> 00:42:55,630 +the second pair it was two and three. + +963 +00:42:55,630 --> 00:42:58,920 +And here we don't really +have that kind of pairs + +964 +00:42:58,920 --> 00:43:00,670 +or anything like that to use. + +965 +00:43:00,670 --> 00:43:04,990 +There is something that we'll +often use for ids called UUID. + +966 +00:43:04,990 --> 00:43:07,750 +This is a very unique identifier. + +967 +00:43:07,750 --> 00:43:11,521 +In the universe it's unique. + +968 +00:43:11,521 --> 00:43:13,020 +It's a little bit of overkill + +969 +00:43:13,020 --> 00:43:15,520 +for the Emojis in EmojiArt. + +970 +00:43:15,520 --> 00:43:17,710 +I could have hundreds +of Emojis in EmojiArt + +971 +00:43:17,710 --> 00:43:19,800 +and I could have hundreds +of EmojiArt documents. + +972 +00:43:19,800 --> 00:43:22,910 +So this is a lot of these, +generating these unique IDs + +973 +00:43:22,910 --> 00:43:24,400 +kind of for nothing. + +974 +00:43:24,400 --> 00:43:27,730 +And really this id also only +needs to be Identifiable + +975 +00:43:27,730 --> 00:43:30,350 +and unique within this document. + +976 +00:43:30,350 --> 00:43:33,580 +We are not going to need to identifiably + +977 +00:43:33,580 --> 00:43:36,300 +see Emoji across many documents. + +978 +00:43:36,300 --> 00:43:40,170 +So I'm going to actually +have this be an Int + +979 +00:43:40,170 --> 00:43:42,980 +which I'm gonna manage in this struct. + +980 +00:43:42,980 --> 00:43:45,210 +And so it's gonna be privately managed. + +981 +00:43:45,210 --> 00:43:48,480 +Only EmojiArt is going +to know what makes this + +982 +00:43:48,480 --> 00:43:50,450 +Int how we make this Int. + +983 +00:43:50,450 --> 00:43:52,820 +But of course Identifiable +is a public thing, + +984 +00:43:52,820 --> 00:43:55,250 +so people would look at the Int. + +985 +00:43:55,250 --> 00:43:58,630 +And since we only want anyone +to ever look at this file, + +986 +00:43:58,630 --> 00:44:01,890 +you can certainly make it a let. + +987 +00:44:01,890 --> 00:44:05,130 +But what we need to do now is +every time this is created, + +988 +00:44:05,130 --> 00:44:07,280 +I give it a unique ID. + +989 +00:44:07,280 --> 00:44:11,090 +And that is going to be done +with a little private var + +990 +00:44:11,090 --> 00:44:12,730 +called uniqueEmojiId. + +991 +00:44:15,204 --> 00:44:17,660 +It's just gonna be an Int +and I'm gonna add a function + +992 +00:44:17,660 --> 00:44:18,823 +called addEmoji. + +993 +00:44:23,968 --> 00:44:26,820 +And all addEmoji is +gonna do is add an Emoji + +994 +00:44:26,820 --> 00:44:31,010 +by appending a new Emoji +which I'm gonna create + +995 +00:44:31,010 --> 00:44:33,053 +with a standard constructor there. + +996 +00:44:35,340 --> 00:44:39,313 +And unique ID as the id. + +997 +00:44:40,230 --> 00:44:43,900 +Now of course I need to keep +this unique ID being unique + +998 +00:44:43,900 --> 00:44:45,650 +so each time someone does this, + +999 +00:44:45,650 --> 00:44:49,900 +I'm gonna say uniqueEmojiID += 1. + +1000 +00:44:49,900 --> 00:44:53,670 +That way it's changing all the +time and always being unique. + +1001 +00:44:53,670 --> 00:44:56,130 +Now this is great, but you +can see I've got errors here + +1002 +00:44:56,130 --> 00:44:56,963 +all over the place. + +1003 +00:44:56,963 --> 00:44:59,237 +"Left side of mutating +operator isn't mutable. + +1004 +00:44:59,237 --> 00:45:01,700 +"Self is immutable, self +is immutable." (chuckles) + +1005 +00:45:01,700 --> 00:45:05,010 +And yes, this is a function +that mutates self, right? + +1006 +00:45:05,010 --> 00:45:06,500 +It changes this guy. + +1007 +00:45:06,500 --> 00:45:09,553 +So we need to mark this +as a mutating func. + +1008 +00:45:11,240 --> 00:45:14,080 +Now this strategy of +doing this uniqueEmojiID + +1009 +00:45:14,080 --> 00:45:17,270 +will work great as long as +everyone always adds Emojis + +1010 +00:45:17,270 --> 00:45:18,950 +by calling addEmoji. + +1011 +00:45:18,950 --> 00:45:22,570 +But what if someone creates +an Emoji with their own id + +1012 +00:45:22,570 --> 00:45:25,930 +and then adds it right here to this Array? + +1013 +00:45:25,930 --> 00:45:28,240 +That could be bad, especially +if they choose an id + +1014 +00:45:28,240 --> 00:45:30,800 +that's the same as some other one we chose + +1015 +00:45:30,800 --> 00:45:32,440 +with that Emoji. + +1016 +00:45:32,440 --> 00:45:35,180 +Now you might think private set, right, + +1017 +00:45:35,180 --> 00:45:36,990 +private set ought to fix this problem + +1018 +00:45:36,990 --> 00:45:38,440 +because that makes it so that emojis + +1019 +00:45:38,440 --> 00:45:41,010 +can only be written by us. + +1020 +00:45:41,010 --> 00:45:43,290 +But I actually don't want that + +1021 +00:45:43,290 --> 00:45:46,410 +because some of these Emoji +things like the position + +1022 +00:45:46,410 --> 00:45:50,056 +and the size I do want +people to set those. + +1023 +00:45:50,056 --> 00:45:50,970 +And they can set them all they want, + +1024 +00:45:50,970 --> 00:45:53,380 +move the emojis around +as much as they want. + +1025 +00:45:53,380 --> 00:45:55,490 +So I really can't use private set here + +1026 +00:45:55,490 --> 00:45:57,150 +like I did in Memorize. + +1027 +00:45:58,150 --> 00:46:01,120 +So how am I going to +protect this from happening + +1028 +00:46:01,120 --> 00:46:04,223 +where people are adding +Emoji, not calling this. + +1029 +00:46:05,407 --> 00:46:06,930 +I'm gonna do that in an interesting way. + +1030 +00:46:06,930 --> 00:46:10,060 +In Emoji here, I'm going to define an init + +1031 +00:46:10,060 --> 00:46:13,290 +and it's gonna have all the same arguments + +1032 +00:46:13,290 --> 00:46:17,590 +as the standard init that you +get for free for a struct. + +1033 +00:46:17,590 --> 00:46:19,450 +Now how does this help the problem? + +1034 +00:46:19,450 --> 00:46:21,040 +In fact, it seems like a big waste. + +1035 +00:46:21,040 --> 00:46:24,297 +I get this for free, why +would I do this at all? + +1036 +00:46:24,297 --> 00:46:25,750 +And the reason I'm gonna do it + +1037 +00:46:25,750 --> 00:46:29,470 +is because I'm gonna +make this init private. + +1038 +00:46:29,470 --> 00:46:31,320 +By making this init private, + +1039 +00:46:31,320 --> 00:46:34,620 +now nobody can create an Emoji + +1040 +00:46:34,620 --> 00:46:37,700 +except for Emoji itself, +it's kinda not useful here. + +1041 +00:46:37,700 --> 00:46:40,890 +Even EmojiArt though can't create it. + +1042 +00:46:40,890 --> 00:46:43,247 +So it does protect against +someone else creating an Emoji + +1043 +00:46:43,247 --> 00:46:45,850 +and putting it in here but +it's protecting EmojiArt + +1044 +00:46:45,850 --> 00:46:47,640 +from doing it too. + +1045 +00:46:47,640 --> 00:46:49,070 +I'm gonna show you a way around that + +1046 +00:46:49,070 --> 00:46:52,603 +with a different kind of access +control called fileprivate. + +1047 +00:46:54,118 --> 00:46:57,450 +fileprivate makes this +private in this file. + +1048 +00:46:57,450 --> 00:47:00,710 +And that gives EmojiArt +the power to call this + +1049 +00:47:00,710 --> 00:47:04,240 +and create this but no one +outside this file can do it. + +1050 +00:47:04,240 --> 00:47:06,100 +So now we've protected against that case + +1051 +00:47:06,100 --> 00:47:09,140 +where someone creates an +Emoji and puts it in here + +1052 +00:47:09,140 --> 00:47:12,300 +without going through +our nice unique EmojiID + +1053 +00:47:12,300 --> 00:47:14,823 +since there's no way for +them to create an Emoji. + +1054 +00:47:16,080 --> 00:47:19,340 +All right, so that's it +basically for our Model. + +1055 +00:47:19,340 --> 00:47:21,160 +Our Model is very simple. + +1056 +00:47:21,160 --> 00:47:24,900 +Let's go over to our ViewModel over here + +1057 +00:47:24,900 --> 00:47:29,850 +and add this as a @Published private var. + +1058 +00:47:29,850 --> 00:47:31,940 +And again, I could call it +Model but I'm not going to. + +1059 +00:47:31,940 --> 00:47:36,300 +I'm gonna call this my +emojiArt, it's of type EmojiArt. + +1060 +00:47:36,300 --> 00:47:39,320 +And let's just set it to a empty EmojiArt + +1061 +00:47:39,320 --> 00:47:44,130 +with no background and +no emoji to start with. + +1062 +00:47:44,130 --> 00:47:47,700 +And it's published because +every time the EmojiArt changes + +1063 +00:47:47,700 --> 00:47:50,750 +of course we need to use our +ObservableObject mechanism + +1064 +00:47:50,750 --> 00:47:52,870 +to cause our View to redraw. + +1065 +00:47:52,870 --> 00:47:56,610 +And it's private because +I'm going to be a very good + +1066 +00:47:56,610 --> 00:47:59,270 +little ViewModel here +and do one of my jobs + +1067 +00:47:59,270 --> 00:48:02,220 +which is to interpret +the Model for the View. + +1068 +00:48:02,220 --> 00:48:06,490 +So I'm a UI guy, I'm a UI +person, this ViewModel. + +1069 +00:48:06,490 --> 00:48:09,050 +I know that we use CGFloats and CGPoints + +1070 +00:48:11,106 --> 00:48:13,520 +and CGSizes, we don't use Ints. + +1071 +00:48:13,520 --> 00:48:16,210 +And I know that's what +my View's gonna expect. + +1072 +00:48:16,210 --> 00:48:18,950 +So I'm going to provide some Intents. + +1073 +00:48:20,440 --> 00:48:23,433 +Mark Intents here. + +1074 +00:48:24,320 --> 00:48:25,867 +And these Intents, we're gonna type 'em in + +1075 +00:48:25,867 --> 00:48:28,220 +real fast there (chuckles) with a snippet. + +1076 +00:48:28,220 --> 00:48:31,110 +These Intents are going to +essentially take arguments + +1077 +00:48:31,110 --> 00:48:34,430 +to addEmoji like at location CGPoint + +1078 +00:48:34,430 --> 00:48:35,980 +and size CGFloat, + +1079 +00:48:35,980 --> 00:48:39,370 +or moveEmoji by offset CGSize, + +1080 +00:48:39,370 --> 00:48:41,020 +or scaleEmoji by a scale CGFloat. + +1081 +00:48:42,752 --> 00:48:43,890 +And then it's just going to turn around + +1082 +00:48:43,890 --> 00:48:47,120 +and access its Array, but Intifying them. + +1083 +00:48:47,120 --> 00:48:49,650 +See, Int, Int, we're doing Int. + +1084 +00:48:49,650 --> 00:48:51,570 +We're making these things into Ints. + +1085 +00:48:51,570 --> 00:48:54,350 +So this makes it so my +View is gonna call these. + +1086 +00:48:54,350 --> 00:48:56,670 +It can't access emojiArt +directly, it's private. + +1087 +00:48:56,670 --> 00:48:58,353 +So it's gonna call these Intent functions, + +1088 +00:48:58,353 --> 00:49:00,540 +intend, I intend to add an Emoji, + +1089 +00:49:00,540 --> 00:49:03,223 +I intend to move Emoji around, et cetera. + +1090 +00:49:04,290 --> 00:49:05,627 +Now notice we have an error here. + +1091 +00:49:05,627 --> 00:49:08,070 +"Cannot convert value type +EmojiArt," blah blah blah. + +1092 +00:49:08,070 --> 00:49:10,580 +It's because I'm using +firstIndex matching. + +1093 +00:49:10,580 --> 00:49:13,010 +Remember that cool function that we added + +1094 +00:49:13,010 --> 00:49:16,030 +via an extension to Array +that would look up something + +1095 +00:49:16,030 --> 00:49:19,000 +that's Identifiable in +an Array of Identifiables + +1096 +00:49:19,000 --> 00:49:21,020 +and find the index of it? + +1097 +00:49:21,020 --> 00:49:23,020 +And I'm doing this inside my ViewModel + +1098 +00:49:23,020 --> 00:49:25,610 +'cause I also don't want +my View to necessarily + +1099 +00:49:25,610 --> 00:49:28,150 +have to deal with indexes into the Array. + +1100 +00:49:28,150 --> 00:49:31,300 +Now in Memorize, we used +index into the Array + +1101 +00:49:31,300 --> 00:49:33,660 +and why did we use index into the Array? + +1102 +00:49:33,660 --> 00:49:35,990 +Because we wanted to +make changes to the Array + +1103 +00:49:35,990 --> 00:49:38,700 +right in place and we want +to do the same thing here. + +1104 +00:49:38,700 --> 00:49:40,800 +So I'm gonna use index as Array here. + +1105 +00:49:40,800 --> 00:49:43,360 +But I'd really like for +my View to just be able + +1106 +00:49:43,360 --> 00:49:45,440 +to use EmojiArt objects. + +1107 +00:49:45,440 --> 00:49:47,360 +And since they're +Identifiable, when they ask me + +1108 +00:49:47,360 --> 00:49:50,320 +to move one or to scale one, + +1109 +00:49:50,320 --> 00:49:53,240 +I'll just use this firstIndex matching + +1110 +00:49:53,240 --> 00:49:56,850 +to look it up by the same +Identifiable that's here + +1111 +00:49:56,850 --> 00:50:00,160 +that's in my emojiArt Emojis list, + +1112 +00:50:00,160 --> 00:50:02,017 +all right, since these are Identifiable. + +1113 +00:50:02,017 --> 00:50:05,200 +And just a little different +API here than having to View, + +1114 +00:50:05,200 --> 00:50:09,223 +have to say moveEmoji at index by offset. + +1115 +00:50:10,350 --> 00:50:13,620 +Now of course firstIndex +matching was something we added + +1116 +00:50:13,620 --> 00:50:16,170 +in Memorize, so it's not here, +that's why it's complaining. + +1117 +00:50:16,170 --> 00:50:19,060 +Now I actually put it in here, this file, + +1118 +00:50:19,060 --> 00:50:21,420 +which I'm gonna drag in +and which I provided to you + +1119 +00:50:21,420 --> 00:50:25,310 +and I'm definitely gonna +copy this in, not link it in. + +1120 +00:50:25,310 --> 00:50:28,940 +And this extension not only +has this firstIndex matching, + +1121 +00:50:28,940 --> 00:50:31,623 +it has some other stuff +you're gonna see later on, + +1122 +00:50:32,470 --> 00:50:34,240 +things that are just kinda of utilities + +1123 +00:50:34,240 --> 00:50:37,060 +and make the code, this +demo go a little quicker. + +1124 +00:50:37,060 --> 00:50:39,920 +And here's firstIndex but +it's kind of interesting, + +1125 +00:50:39,920 --> 00:50:42,220 +I didn't add it to Array. + +1126 +00:50:42,220 --> 00:50:45,860 +Here we did Array in our Memorize, + +1127 +00:50:45,860 --> 00:50:48,960 +but here I'm doing collection, +now what is collection? + +1128 +00:50:48,960 --> 00:50:51,990 +Collection is a protocol +that Array implements. + +1129 +00:50:51,990 --> 00:50:54,320 +And since Array implements that protocol, + +1130 +00:50:54,320 --> 00:50:57,760 +if I add an extension +to it, Array gets this. + +1131 +00:50:57,760 --> 00:50:59,420 +And so this will work with any collection. + +1132 +00:50:59,420 --> 00:51:02,380 +Now why did I add it to +collection here instead of Array? + +1133 +00:51:02,380 --> 00:51:07,380 +Well because Set also +implements a collection. + +1134 +00:51:07,650 --> 00:51:10,510 +So if I have a Set, you +know, the SwiftUI Set + +1135 +00:51:10,510 --> 00:51:11,940 +not the set your homework +three. (chuckles) + +1136 +00:51:11,940 --> 00:51:14,190 +SwiftUI Set, if I have one of those + +1137 +00:51:14,190 --> 00:51:17,500 +I can do firstIndex +matching on it as well. + +1138 +00:51:17,500 --> 00:51:22,500 +And I'm even gonna put this +contains matching element also + +1139 +00:51:23,090 --> 00:51:27,390 +so that I can go look and see +inside of a Set or an Array, + +1140 +00:51:27,390 --> 00:51:30,973 +do you contain this thing by matching it? + +1141 +00:51:32,120 --> 00:51:35,083 +So I'm doing the same +$0 equals element.id. + +1142 +00:51:36,020 --> 00:51:37,600 +Why do I do that, by the way? + +1143 +00:51:37,600 --> 00:51:40,340 +Well I think when you +do your assignment four + +1144 +00:51:40,340 --> 00:51:41,350 +and you're having to manage + +1145 +00:51:41,350 --> 00:51:43,230 +the selection of all those Emojis, + +1146 +00:51:43,230 --> 00:51:45,600 +pretty good chance you might +want to put them in a Set. + +1147 +00:51:45,600 --> 00:51:47,340 +You probably could put 'em into an Array, + +1148 +00:51:47,340 --> 00:51:50,320 +but Sets are nicer than Arrays +because they manage identity + +1149 +00:51:50,320 --> 00:51:52,000 +and you never want the same Emoji + +1150 +00:51:52,000 --> 00:51:55,120 +inside of your selection twice. + +1151 +00:51:55,120 --> 00:51:58,190 +And it's real easy to take 'em +in and put 'em out in a set. + +1152 +00:51:58,190 --> 00:52:00,820 +So if you want to do that, +you don't have to use this. + +1153 +00:52:00,820 --> 00:52:03,730 +So any of this stuff, +okay, this is just provided + +1154 +00:52:03,730 --> 00:52:06,150 +for your use if you want to, +but you might want to use Sets. + +1155 +00:52:06,150 --> 00:52:08,573 +So that's why I'm putting that here. + +1156 +00:52:09,907 --> 00:52:10,950 +All right, back to our ViewModel. + +1157 +00:52:10,950 --> 00:52:14,040 +Now if we compile on +this side, it'll succeed + +1158 +00:52:14,040 --> 00:52:17,687 +and we have built our +Intents here for the emojis. + +1159 +00:52:17,687 --> 00:52:20,010 +But there's one more Intent I might have + +1160 +00:52:20,010 --> 00:52:22,370 +which is to set the background URL, + +1161 +00:52:22,370 --> 00:52:24,120 +which I'm gonna do with drag and drop. + +1162 +00:52:24,120 --> 00:52:27,297 +So I need one more here which +is func setBackgroundURL + +1163 +00:52:28,370 --> 00:52:31,840 +and it's just going to +take a URL here, URL, + +1164 +00:52:31,840 --> 00:52:35,780 +type URL, again optional, we allow that. + +1165 +00:52:35,780 --> 00:52:38,767 +And we'll just have our +emojiArt.backgroundURL + +1166 +00:52:40,200 --> 00:52:41,290 +equal this URL. + +1167 +00:52:41,290 --> 00:52:44,180 +I'm gonna do one other +little thing right here + +1168 +00:52:44,180 --> 00:52:47,130 +which is that these URLS +that you drag and drop + +1169 +00:52:47,130 --> 00:52:50,710 +from the internet, sometimes +they're kinda funky URLs + +1170 +00:52:50,710 --> 00:52:53,420 +that have the actual URL +(chuckles) for the image + +1171 +00:52:53,420 --> 00:52:55,410 +embedded inside of them using this thing + +1172 +00:52:55,410 --> 00:52:59,310 +called image URL right here, I-M-G-U-R-L. + +1173 +00:52:59,310 --> 00:53:04,100 +So I put a little thing on +URL to extract that image URL + +1174 +00:53:04,100 --> 00:53:07,600 +if it's in there out of +these more complicated URLs. + +1175 +00:53:07,600 --> 00:53:10,593 +So I'm gonna call this little +imageURL var right here. + +1176 +00:53:12,490 --> 00:53:14,900 +Okay, and if, by the way, +if imageURL goes and looks + +1177 +00:53:14,900 --> 00:53:17,380 +and it can't find that +funky little embedded thing + +1178 +00:53:17,380 --> 00:53:19,050 +then it just returns the URL itself. + +1179 +00:53:19,050 --> 00:53:22,750 +So if you drag a normal URL +in, that'll work as well. + +1180 +00:53:22,750 --> 00:53:26,830 +So now our ViewModel is fully prepared + +1181 +00:53:26,830 --> 00:53:30,860 +to support the View in doing +what the View wants to do. + +1182 +00:53:30,860 --> 00:53:34,660 +And so let's go over to +our View and implement it. + +1183 +00:53:34,660 --> 00:53:36,250 +Now the first thing I want to implement + +1184 +00:53:36,250 --> 00:53:38,090 +is that drag and drop all right. + +1185 +00:53:38,090 --> 00:53:40,410 +So over here in our simulator, + +1186 +00:53:40,410 --> 00:53:43,380 +if we have our EmojiArt +with Safari on here + +1187 +00:53:43,380 --> 00:53:45,370 +and I pick this up, I want to be able + +1188 +00:53:45,370 --> 00:53:48,607 +to drop it in here but notice +it's really not working. + +1189 +00:53:48,607 --> 00:53:50,740 +It, I don't know, when +we did it the first time + +1190 +00:53:50,740 --> 00:53:52,590 +you noticed there was a little green plus. + +1191 +00:53:52,590 --> 00:53:55,180 +I'm not getting the green +plus and when I let go, + +1192 +00:53:55,180 --> 00:53:58,030 +it doesn't, it fails +to drop and goes back. + +1193 +00:53:58,030 --> 00:53:59,850 +So I want it to drop and +I want it to draw here. + +1194 +00:53:59,850 --> 00:54:01,590 +I'm also not gonna be yellow anymore. + +1195 +00:54:01,590 --> 00:54:02,990 +I'm gonna use a white background. + +1196 +00:54:02,990 --> 00:54:05,270 +I think that looks better +when we don't have an image + +1197 +00:54:05,270 --> 00:54:07,460 +or if our image is small, having white's + +1198 +00:54:07,460 --> 00:54:09,720 +gonna look better than yellow. + +1199 +00:54:09,720 --> 00:54:11,230 +So let's do this drag and drop. + +1200 +00:54:11,230 --> 00:54:13,760 +Now before we go do drag and +drop, a couple of things. + +1201 +00:54:13,760 --> 00:54:16,670 +First of all, this only works in iOS 13.4. + +1202 +00:54:16,670 --> 00:54:19,400 +So if you're not on the latest Xcode, + +1203 +00:54:19,400 --> 00:54:22,540 +this part of this demo, it's +just not going to work for you. + +1204 +00:54:22,540 --> 00:54:25,960 +The second thing is drag and drop, + +1205 +00:54:25,960 --> 00:54:28,223 +it's a little bit of sophisticated API. + +1206 +00:54:28,223 --> 00:54:33,040 +It's very simple in SwiftUI, +but it uses some old technology + +1207 +00:54:33,040 --> 00:54:35,290 +from the Objective-C world. + +1208 +00:54:35,290 --> 00:54:39,670 +And so don't be too caught +up in the details of this. + +1209 +00:54:39,670 --> 00:54:42,010 +I want you to conceptually +understand what's going on. + +1210 +00:54:42,010 --> 00:54:44,810 +I'm not gonna ask you to do +drag and drop in your homework + +1211 +00:54:44,810 --> 00:54:45,740 +but it might be something you want to do + +1212 +00:54:45,740 --> 00:54:48,320 +in your final project so this +would be a good opportunity + +1213 +00:54:48,320 --> 00:54:50,370 +to understand it from that point of view. + +1214 +00:54:51,360 --> 00:54:53,370 +So drag and drop works very simply. + +1215 +00:54:53,370 --> 00:54:55,780 +You just call this method +on anywhere you want + +1216 +00:54:55,780 --> 00:54:57,947 +to be able drop, you just say onDrop. + +1217 +00:54:58,990 --> 00:55:02,270 +And onDrop takes some argument +here which I'm gonna type + +1218 +00:55:02,270 --> 00:55:04,830 +in and then we'll go over what they are. + +1219 +00:55:04,830 --> 00:55:08,830 +This first argument of, this +is saying what kind of thing + +1220 +00:55:08,830 --> 00:55:13,670 +do you want to drop and we +want to drop public image. + +1221 +00:55:13,670 --> 00:55:16,673 +So public image is a, what's called a URI. + +1222 +00:55:17,510 --> 00:55:20,660 +It specifies kind of a public agreement + +1223 +00:55:20,660 --> 00:55:24,520 +of the type of things that are images. + +1224 +00:55:24,520 --> 00:55:27,290 +Now we're looking for a URL, not an image. + +1225 +00:55:27,290 --> 00:55:31,890 +But if you drag and drop an +image, very likely the provider + +1226 +00:55:31,890 --> 00:55:35,180 +of that image can also +provide you its URL. + +1227 +00:55:35,180 --> 00:55:37,340 +So that is what we are +going to have dropped. + +1228 +00:55:37,340 --> 00:55:40,400 +If I said in here that +we wanted URLs dropped, + +1229 +00:55:40,400 --> 00:55:42,330 +we might get URLs from non-images + +1230 +00:55:42,330 --> 00:55:43,340 +that would be useless to us. + +1231 +00:55:43,340 --> 00:55:45,120 +So that why the kind +of thing we're looking + +1232 +00:55:45,120 --> 00:55:46,820 +to be dropping here is images. + +1233 +00:55:46,820 --> 00:55:48,670 +Now I'm not gonna talk about URIs. + +1234 +00:55:48,670 --> 00:55:50,370 +You can look up URIs in the documentation + +1235 +00:55:50,370 --> 00:55:51,860 +and understand what they are. + +1236 +00:55:51,860 --> 00:55:53,910 +We're actually gonna +put another one in here + +1237 +00:55:53,910 --> 00:55:57,100 +in a few minutes, but it's +pretty straightforward + +1238 +00:55:57,100 --> 00:55:58,660 +what a URI is. + +1239 +00:55:58,660 --> 00:56:00,300 +Now this isTargeted. + +1240 +00:56:00,300 --> 00:56:03,710 +That is a good thing we don't need this + +1241 +00:56:03,710 --> 00:56:06,190 +because the argument to this +is what's called a Binding. + +1242 +00:56:06,190 --> 00:56:08,730 +We're gonna talk all +about Bindings next week. + +1243 +00:56:08,730 --> 00:56:10,400 +But we haven't talked about 'em yet + +1244 +00:56:10,400 --> 00:56:12,960 +so if I had to explain it +now, that would be bad. + +1245 +00:56:12,960 --> 00:56:16,160 +But all this is doing is +basically letting us know + +1246 +00:56:16,160 --> 00:56:18,190 +when someone's dragging over us. + +1247 +00:56:18,190 --> 00:56:20,310 +Not when they drop, but +when they're dragging over. + +1248 +00:56:20,310 --> 00:56:22,090 +Luckily I don't care, I just care + +1249 +00:56:22,090 --> 00:56:23,693 +when you drop that thing on me. + +1250 +00:56:24,550 --> 00:56:27,570 +And then the third argument +to onDrop is a function, + +1251 +00:56:27,570 --> 00:56:29,510 +a closure, that has two arguments. + +1252 +00:56:29,510 --> 00:56:31,050 +One is providers. + +1253 +00:56:31,050 --> 00:56:34,470 +These are objects called NSItemProviders + +1254 +00:56:34,470 --> 00:56:37,850 +that provide the information +that's being dropped. + +1255 +00:56:37,850 --> 00:56:40,340 +Now this information being +dropped might be big, + +1256 +00:56:40,340 --> 00:56:41,660 +like it might actually be an image. + +1257 +00:56:41,660 --> 00:56:43,120 +We're only gonna grab the URL, + +1258 +00:56:43,120 --> 00:56:45,980 +but you could grab the +whole image and that's big. + +1259 +00:56:45,980 --> 00:56:48,550 +And so that transfer has +to happen asynchronously + +1260 +00:56:48,550 --> 00:56:51,680 +and we're gonna talk all +about asynchrony in this demo. + +1261 +00:56:51,680 --> 00:56:54,040 +That's one of the primary +things we're doing in this demo. + +1262 +00:56:54,040 --> 00:56:56,670 +But we're not, we're gonna +gloss over the asynchrony here + +1263 +00:56:56,670 --> 00:56:58,010 +in these providers. + +1264 +00:56:58,010 --> 00:57:01,680 +I put again some code over +here in this EmojiArtExtensions + +1265 +00:57:01,680 --> 00:57:03,750 +to handle that stuff for us. + +1266 +00:57:03,750 --> 00:57:06,180 +And so don't worry about +the asynchrony of this. + +1267 +00:57:06,180 --> 00:57:09,467 +We'll be talking all about +asynchrony in just a moment here. + +1268 +00:57:09,467 --> 00:57:11,400 +And then the second +argument to this function + +1269 +00:57:11,400 --> 00:57:12,540 +is the location of the drop. + +1270 +00:57:12,540 --> 00:57:15,030 +Now for the background, we +don't care where it was dropped. + +1271 +00:57:15,030 --> 00:57:18,230 +You drop it anywhere in +our big yellow, currently, + +1272 +00:57:18,230 --> 00:57:19,950 +rectangle, we're gonna accept the drop. + +1273 +00:57:19,950 --> 00:57:21,590 +So we're not gonna do anything +with location for now. + +1274 +00:57:21,590 --> 00:57:23,467 +But eventually we're gonna +be dropping emoji on there + +1275 +00:57:23,467 --> 00:57:26,910 +and then we will care about +location, but not yet. + +1276 +00:57:26,910 --> 00:57:28,520 +So what do we have to do in here? + +1277 +00:57:28,520 --> 00:57:30,550 +This function that we're given is supposed + +1278 +00:57:30,550 --> 00:57:33,600 +to return whether the drop succeeded. + +1279 +00:57:33,600 --> 00:57:35,800 +So I'm gonna create another +little function for that + +1280 +00:57:35,800 --> 00:57:38,663 +called drop with the providers, + +1281 +00:57:40,010 --> 00:57:41,858 +pass those providers over. + +1282 +00:57:41,858 --> 00:57:44,333 +And it's gonna return +whether the drop succeeded. + +1283 +00:57:45,370 --> 00:57:46,830 +So, just gonna do that. + +1284 +00:57:46,830 --> 00:57:50,550 +A little private func +here, drop providers. + +1285 +00:57:50,550 --> 00:57:52,080 +And these providers are an Array + +1286 +00:57:52,080 --> 00:57:54,990 +of, as I said, NSItemProvider. + +1287 +00:57:54,990 --> 00:57:57,674 +This thing, I'm not gonna +get into what this is. + +1288 +00:57:57,674 --> 00:58:00,620 +It's kind of an old +Objective-C thing right there. + +1289 +00:58:00,620 --> 00:58:02,650 +And this returns a Bool with it, + +1290 +00:58:02,650 --> 00:58:05,390 +which is whether the drop succeeded. + +1291 +00:58:05,390 --> 00:58:08,010 +All we need to do here because +of that little extension + +1292 +00:58:08,010 --> 00:58:12,530 +I provided is go try and load +a URL from these providers, + +1293 +00:58:12,530 --> 00:58:14,910 +see if these providers can +provide me an actual URL. + +1294 +00:58:14,910 --> 00:58:16,980 +I'm asking for images, so +they might not be able to + +1295 +00:58:16,980 --> 00:58:18,950 +but usually they do. + +1296 +00:58:18,950 --> 00:58:23,340 +So I'm gonna let a little +variable found equal providers + +1297 +00:58:23,340 --> 00:58:25,420 +that's the Array of those item providers, + +1298 +00:58:25,420 --> 00:58:27,480 +load up the first object + +1299 +00:58:28,590 --> 00:58:29,593 +of type URL. + +1300 +00:58:31,940 --> 00:58:34,170 +And when you specify type as an argument, + +1301 +00:58:34,170 --> 00:58:38,070 +you say URL.self, that +means the actual type URL. + +1302 +00:58:38,070 --> 00:58:42,050 +This just a static var in the type URL + +1303 +00:58:42,050 --> 00:58:44,539 +that returns the type itself. + +1304 +00:58:44,539 --> 00:58:47,820 +And that works for instances, +it also works for classes. + +1305 +00:58:47,820 --> 00:58:48,840 +So I'm able to do that. + +1306 +00:58:48,840 --> 00:58:51,730 +Then it calls a little +function where it passes you + +1307 +00:58:51,730 --> 00:58:54,500 +the URL that it was able to find. + +1308 +00:58:54,500 --> 00:58:56,010 +And this is just the URL that it was able + +1309 +00:58:56,010 --> 00:58:58,280 +to load the first one of. + +1310 +00:58:58,280 --> 00:59:02,330 +And all we need to do now +is just ask our document, + +1311 +00:59:02,330 --> 00:59:05,260 +our ViewModel, to please +set the background URL + +1312 +00:59:05,260 --> 00:59:07,710 +to this thing that was just dropped on me. + +1313 +00:59:07,710 --> 00:59:08,810 +To make sure this is working, + +1314 +00:59:08,810 --> 00:59:12,473 +I'm gonna actually print +out here dropped URL + +1315 +00:59:13,980 --> 00:59:16,900 +and print out what was dropped on this. + +1316 +00:59:16,900 --> 00:59:18,720 +So it would make sure +that this dropping stuff + +1317 +00:59:18,720 --> 00:59:21,740 +is actually working +before go and figure out + +1318 +00:59:21,740 --> 00:59:23,673 +how to get this URL to show up. + +1319 +00:59:24,920 --> 00:59:25,980 +So I'm gonna return this found + +1320 +00:59:25,980 --> 00:59:27,310 +whether or not the drop worked, + +1321 +00:59:27,310 --> 00:59:30,860 +that's what loadFirstObject +return is whether it worked. + +1322 +00:59:30,860 --> 00:59:32,800 +That's it for drag and drop. (chuckles) + +1323 +00:59:32,800 --> 00:59:36,110 +This is really simple +actually to do drag and drop. + +1324 +00:59:36,110 --> 00:59:38,450 +The complication comes a +little bit inside here. + +1325 +00:59:38,450 --> 00:59:41,690 +I encourage you if you want +to understand drag and drop + +1326 +00:59:41,690 --> 00:59:44,610 +to go and see if you can +figure out that code. + +1327 +00:59:44,610 --> 00:59:46,100 +So let's run and see if we're at least + +1328 +00:59:46,100 --> 00:59:47,663 +getting this print to happen. + +1329 +00:59:51,842 --> 00:59:54,540 +There we go, so I'm gonna +pick up our image, drag. + +1330 +00:59:54,540 --> 00:59:56,630 +I can already see something's different. + +1331 +00:59:56,630 --> 00:59:59,060 +The green plus that's +appearing in the corner + +1332 +00:59:59,060 --> 01:00:01,420 +of the image, that's good, and drop. + +1333 +01:00:01,420 --> 01:00:03,610 +And it didn't do anything, of course, + +1334 +01:00:03,610 --> 01:00:06,110 +'cause we don't do anything with the URL. + +1335 +01:00:06,110 --> 01:00:11,110 +But it did do it here, down +here, saying dropped this URL + +1336 +01:00:11,750 --> 01:00:13,170 +and in fact this is one of those URLs + +1337 +01:00:13,170 --> 01:00:17,310 +that has this weird imgurl +thing embedded in it. + +1338 +01:00:17,310 --> 01:00:20,020 +See, this is the actual URL there. + +1339 +01:00:20,020 --> 01:00:22,240 +So it's good thing we dragged, you know, + +1340 +01:00:22,240 --> 01:00:25,247 +dragged this thing out of +here or this would not work. + +1341 +01:00:25,247 --> 01:00:26,080 +But this is great. + +1342 +01:00:26,080 --> 01:00:28,440 +So we have this URL, we +set it as our document's + +1343 +01:00:28,440 --> 01:00:32,250 +background URL in our +ViewModel, setBackgroundURL, + +1344 +01:00:32,250 --> 01:00:34,987 +which sets it in our Model over here. + +1345 +01:00:34,987 --> 01:00:36,570 +And all is well. + +1346 +01:00:36,570 --> 01:00:38,010 +The only thing that's left to do now + +1347 +01:00:38,010 --> 01:00:40,908 +is actually show that image. (chuckles) + +1348 +01:00:40,908 --> 01:00:42,650 +All right, we've got +the URL of that image, + +1349 +01:00:42,650 --> 01:00:45,200 +but nowhere in our View right here + +1350 +01:00:45,200 --> 01:00:46,607 +do we actually show the image. + +1351 +01:00:46,607 --> 01:00:48,750 +All we show now is a rectangle, + +1352 +01:00:48,750 --> 01:00:50,890 +edges ignoring that takes a drop. + +1353 +01:00:50,890 --> 01:00:53,453 +So how are we going to do that? + +1354 +01:00:53,453 --> 01:00:55,410 +We need to do that +essentially by replacing + +1355 +01:00:55,410 --> 01:00:58,537 +this Rectangle +foregroundColor yellow here. + +1356 +01:00:58,537 --> 01:01:02,030 +I'm gonna replace it by making +it be a white Rectangle. + +1357 +01:01:02,030 --> 01:01:06,390 +And overlaid on top of it +is going to be an Image + +1358 +01:01:06,390 --> 01:01:11,150 +that has our document's backgroundImage. + +1359 +01:01:11,150 --> 01:01:14,310 +Now this line of code's +got a lot to unpack here. + +1360 +01:01:14,310 --> 01:01:17,020 +So let's unpack this piece +by piece what's going on here + +1361 +01:01:17,020 --> 01:01:19,720 +'cause it's not actually gonna work as-is. + +1362 +01:01:19,720 --> 01:01:22,840 +The first thing is I +took a white Rectangle + +1363 +01:01:22,840 --> 01:01:25,640 +and I overlaid my Image on top of it. + +1364 +01:01:25,640 --> 01:01:27,520 +Why did I do that, why didn't I just + +1365 +01:01:27,520 --> 01:01:29,650 +make a ZStack here, right? + +1366 +01:01:29,650 --> 01:01:32,600 +ZStack overlays one +View on top of another. + +1367 +01:01:32,600 --> 01:01:35,600 +And this has to do with sizing + +1368 +01:01:35,600 --> 01:01:39,690 +because we want our +document View, or whatever, + +1369 +01:01:39,690 --> 01:01:43,390 +to be sized like it was a Rectangle. + +1370 +01:01:43,390 --> 01:01:46,190 +Basically we wanted to use +all the space offered to it. + +1371 +01:01:46,190 --> 01:01:48,950 +We know that Shapes take all +the space offered to them + +1372 +01:01:48,950 --> 01:01:50,320 +so that's what we want. + +1373 +01:01:50,320 --> 01:01:53,500 +We wouldn't want it to +size it to the Image + +1374 +01:01:53,500 --> 01:01:57,040 +because Images, these Views, Image, + +1375 +01:01:57,040 --> 01:02:00,210 +they size themselves to +the size of the image. + +1376 +01:02:00,210 --> 01:02:01,300 +So if you had a small image, + +1377 +01:02:01,300 --> 01:02:03,160 +we would have a small little View there + +1378 +01:02:03,160 --> 01:02:05,110 +and we want it to be as big as possible. + +1379 +01:02:05,110 --> 01:02:07,510 +There is also something called background + +1380 +01:02:07,510 --> 01:02:09,360 +which does the same kind of thing. + +1381 +01:02:09,360 --> 01:02:13,630 +Sizes to this and then puts +whatever View is in here + +1382 +01:02:13,630 --> 01:02:15,880 +as a background for the other image. + +1383 +01:02:15,880 --> 01:02:17,210 +So this is all about sizing. + +1384 +01:02:17,210 --> 01:02:22,043 +Using overlay or using +background, all right, right here, + +1385 +01:02:23,068 --> 01:02:26,043 +is all about the sizing +behavior that you want. + +1386 +01:02:27,510 --> 01:02:28,440 +All right, otherwise this is very much + +1387 +01:02:28,440 --> 01:02:31,433 +like a two-View ZStack essentially. + +1388 +01:02:34,180 --> 01:02:37,000 +So it's still not quite right here. + +1389 +01:02:37,000 --> 01:02:39,510 +We're still making our way through this. + +1390 +01:02:39,510 --> 01:02:43,470 +This Image right here, +it takes some argument + +1391 +01:02:43,470 --> 01:02:46,670 +which is supposed to be +this image, backgroundImage, + +1392 +01:02:46,670 --> 01:02:48,550 +but what is backgroundImage? + +1393 +01:02:48,550 --> 01:02:51,910 +We don't have a backgroundImage +in our document. + +1394 +01:02:51,910 --> 01:02:53,300 +So let's add that. + +1395 +01:02:53,300 --> 01:02:56,030 +Let's go over here, I'm +just gonna add a var + +1396 +01:02:56,030 --> 01:03:00,420 +backgroundImage and what +type is this gonna be? + +1397 +01:03:00,420 --> 01:03:03,140 +You'd think this might be a type Image + +1398 +01:03:03,140 --> 01:03:04,760 +but it's not really a type Image. + +1399 +01:03:04,760 --> 01:03:06,770 +We're creating the Image View right here. + +1400 +01:03:06,770 --> 01:03:10,250 +So this type Image, this +is a struct, it's a View. + +1401 +01:03:10,250 --> 01:03:13,580 +Really what we want to pass +to it is an actual image. + +1402 +01:03:13,580 --> 01:03:16,510 +And an actual image in +SwiftUI is represented + +1403 +01:03:16,510 --> 01:03:19,580 +by another thing called a UIImage. + +1404 +01:03:19,580 --> 01:03:22,360 +Now UIImage, things that start with UI + +1405 +01:03:22,360 --> 01:03:27,200 +come from the old world, the +previous-to-SwiftUI world. + +1406 +01:03:27,200 --> 01:03:30,220 +And this was such a great little object + +1407 +01:03:30,220 --> 01:03:33,160 +for dealing with images that +they decided just to keep it. + +1408 +01:03:33,160 --> 01:03:35,643 +And they did the same thing with UIColor. + +1409 +01:03:35,643 --> 01:03:37,410 +And we saw that before that we have Color. + +1410 +01:03:37,410 --> 01:03:40,793 +Color is kind of like a +View, but UIColor is a thing + +1411 +01:03:40,793 --> 01:03:43,420 +that actually represents Colors. + +1412 +01:03:43,420 --> 01:03:46,110 +By the way, I talked about +UIColor being a View. + +1413 +01:03:46,110 --> 01:03:49,310 +UIColor also can be a +specifier right here, + +1414 +01:03:49,310 --> 01:03:51,040 +foregroundColor Color.white. + +1415 +01:03:51,040 --> 01:03:54,650 +This is not a View, we're just +specifying the Color white. + +1416 +01:03:54,650 --> 01:03:57,010 +But Color can act like a View. + +1417 +01:03:57,010 --> 01:03:59,617 +I could even say Color.white right here, + +1418 +01:03:59,617 --> 01:04:01,340 +and that's perfectly legal. (chuckles) + +1419 +01:04:01,340 --> 01:04:02,803 +This can be a View and we also know + +1420 +01:04:02,803 --> 01:04:05,610 +that Color can be ShapeStyle, + +1421 +01:04:05,610 --> 01:04:08,750 +fill Color or stroke Color in a Shape. + +1422 +01:04:08,750 --> 01:04:10,070 +So Color's kind of a chameleon, + +1423 +01:04:10,070 --> 01:04:12,640 +can be a lot of different things. + +1424 +01:04:12,640 --> 01:04:14,320 +But Image here is the View. + +1425 +01:04:14,320 --> 01:04:18,180 +We can say uiImage as +the constructor for it + +1426 +01:04:18,180 --> 01:04:21,550 +and pass it a UIImage and +that will make the Image. + +1427 +01:04:21,550 --> 01:04:23,580 +And we're often doing this +when we create an Image. + +1428 +01:04:23,580 --> 01:04:25,920 +We're gonna learn other +ways to create Images, + +1429 +01:04:25,920 --> 01:04:29,370 +but one way is we just pass it a UIImage. + +1430 +01:04:30,385 --> 01:04:32,370 +Now this isn't quite working either + +1431 +01:04:32,370 --> 01:04:36,020 +and that's because this +does not really want + +1432 +01:04:36,020 --> 01:04:39,003 +to be a UIImage, it's an optional UIImage. + +1433 +01:04:39,950 --> 01:04:42,210 +Because again, we might +not have the background. + +1434 +01:04:42,210 --> 01:04:44,790 +Even if we have the URL, +we might not have gone + +1435 +01:04:44,790 --> 01:04:46,680 +and got the image yet. + +1436 +01:04:46,680 --> 01:04:49,340 +So this has to be able to be nil. + +1437 +01:04:49,340 --> 01:04:50,460 +Another important thing here + +1438 +01:04:50,460 --> 01:04:52,260 +is I want this to be private set. + +1439 +01:04:52,260 --> 01:04:55,860 +Only our ViewModel is +going to be fetching images + +1440 +01:04:55,860 --> 01:04:56,930 +from the internet. + +1441 +01:04:56,930 --> 01:05:00,630 +Our View is just going to +look at whatever image arrives + +1442 +01:05:00,630 --> 01:05:01,623 +from the internet. + +1443 +01:05:02,760 --> 01:05:04,550 +All right, so our View gets the drop, + +1444 +01:05:04,550 --> 01:05:08,550 +it sets the backgroundURL, +and then it's our ViewModel + +1445 +01:05:08,550 --> 01:05:09,900 +that's gonna have to go off + +1446 +01:05:09,900 --> 01:05:12,690 +and create this background image. + +1447 +01:05:12,690 --> 01:05:15,960 +So that creates a problem though, +making this be an optional + +1448 +01:05:15,960 --> 01:05:19,030 +because this Image uiImage constructor + +1449 +01:05:19,030 --> 01:05:20,520 +will not take an optional. + +1450 +01:05:20,520 --> 01:05:22,970 +This has to be non-optional. + +1451 +01:05:22,970 --> 01:05:25,150 +So it kinda makes me want to go in here, + +1452 +01:05:25,150 --> 01:05:26,567 +and say, "Yeah, I'll just have to say + +1453 +01:05:26,567 --> 01:05:29,530 +"if self.document.backgroundImage + +1454 +01:05:31,067 --> 01:05:36,067 +"does not equal nil, then I'll +create this image right here + +1455 +01:05:36,527 --> 01:05:38,900 +"and I'll force unwrap it." + +1456 +01:05:38,900 --> 01:05:42,090 +And this looks like, oh, this should work + +1457 +01:05:42,090 --> 01:05:44,710 +except for the problem is that +the arguments that overlay + +1458 +01:05:44,710 --> 01:05:47,750 +somewhat unusually is not a ViewBuilder. + +1459 +01:05:47,750 --> 01:05:49,530 +This didn't have curly braces, + +1460 +01:05:49,530 --> 01:05:50,690 +there was no curly brace there. + +1461 +01:05:50,690 --> 01:05:54,030 +This is an actual View, +this has to be a View. + +1462 +01:05:54,030 --> 01:05:55,610 +And we can't do ifs here. + +1463 +01:05:55,610 --> 01:05:57,160 +This is supposed to be a View. + +1464 +01:05:57,160 --> 01:05:59,330 +This is an if statement, not a View. + +1465 +01:05:59,330 --> 01:06:02,700 +So if we want to do this nice +ViewBuilder if stuff here, + +1466 +01:06:02,700 --> 01:06:07,010 +we need to wrap this in +something that does ViewBuilder + +1467 +01:06:07,010 --> 01:06:09,700 +and that's what Group is really good at. + +1468 +01:06:09,700 --> 01:06:12,230 +So if you find yourself having +to pass a View somewhere, + +1469 +01:06:12,230 --> 01:06:14,610 +but you need to do the +if business around it, + +1470 +01:06:14,610 --> 01:06:16,210 +go ahead and use a Group because a Group + +1471 +01:06:16,210 --> 01:06:19,440 +does not otherwise modify +the layout or anything + +1472 +01:06:19,440 --> 01:06:23,093 +of that View, so it's a nice +little trick to use Group. + +1473 +01:06:24,490 --> 01:06:25,570 +All right, excellent. + +1474 +01:06:25,570 --> 01:06:28,618 +So everything's fine, no errors, + +1475 +01:06:28,618 --> 01:06:29,490 +(chuckles) everything compiled. + +1476 +01:06:29,490 --> 01:06:32,860 +The only problem is this is +just always going to be nil. + +1477 +01:06:32,860 --> 01:06:34,780 +We never set this to anything. + +1478 +01:06:34,780 --> 01:06:37,570 +Our ViewModel is to take this URL + +1479 +01:06:37,570 --> 01:06:39,530 +and go fetch it on the internet. + +1480 +01:06:39,530 --> 01:06:42,320 +And when it gets the actual +image and makes a UIImage + +1481 +01:06:42,320 --> 01:06:44,760 +out of whatever it finds +over there on the internet, + +1482 +01:06:44,760 --> 01:06:47,440 +then it should automatically +draw in our View. + +1483 +01:06:47,440 --> 01:06:52,223 +As long as we make this +backgroundImage also Published. + +1484 +01:06:53,170 --> 01:06:55,570 +We need to publish this so +that whenever this changes, + +1485 +01:06:55,570 --> 01:06:59,510 +our View causes to redraw and +this whole thing will happen, + +1486 +01:06:59,510 --> 01:07:02,410 +this overlay will change, and +we'll get to see that image. + +1487 +01:07:03,550 --> 01:07:05,790 +Especially when you're +doing your ViewModel, + +1488 +01:07:05,790 --> 01:07:07,667 +it can be easy to remember, +"Oh, yeah, of course, + +1489 +01:07:07,667 --> 01:07:10,250 +"my Model is published." + +1490 +01:07:10,250 --> 01:07:12,930 +But there might be other +things that your ViewModel + +1491 +01:07:12,930 --> 01:07:15,920 +is doing that you want +your View to react to. + +1492 +01:07:15,920 --> 01:07:18,950 +And we just do that with @Published. + +1493 +01:07:18,950 --> 01:07:23,000 +Now really some ways, the meat +of today's lecture (chuckles) + +1494 +01:07:23,000 --> 01:07:26,060 +is how are we gonna fetch +this backgroundImage + +1495 +01:07:26,060 --> 01:07:29,900 +and create a UIImage +from this URL down here? + +1496 +01:07:29,900 --> 01:07:32,060 +We're gonna do that in +its own little function. + +1497 +01:07:32,060 --> 01:07:33,930 +I'm gonna call this function + +1498 +01:07:34,807 --> 01:07:36,890 +fetchBackgroundImageData. + +1499 +01:07:40,225 --> 01:07:42,340 +And it's gonna go fetch +the background image data + +1500 +01:07:42,340 --> 01:07:44,820 +and make a UIImage out of it. + +1501 +01:07:44,820 --> 01:07:45,653 +So let's create that little func, + +1502 +01:07:45,653 --> 01:07:47,760 +it's a little private func here. + +1503 +01:07:47,760 --> 01:07:51,400 +This function's only +job is to set this var. + +1504 +01:07:51,400 --> 01:07:54,490 +Once it sets this var to +some UIImage that it gets + +1505 +01:07:54,490 --> 01:07:57,930 +from this URL, everything's +just gonna update, right. + +1506 +01:07:57,930 --> 01:08:02,240 +We have reactive UI, +we've already built our UI + +1507 +01:08:02,240 --> 01:08:03,460 +to deal with this image. + +1508 +01:08:03,460 --> 01:08:06,450 +So it should all just happen +automatically once we set this. + +1509 +01:08:06,450 --> 01:08:08,590 +So our goal here in the +side here (chuckles) + +1510 +01:08:08,590 --> 01:08:11,563 +is to do one thing and one +thing only, set this var. + +1511 +01:08:13,508 --> 01:08:15,750 +All right, so what are +we gonna do to do that? + +1512 +01:08:15,750 --> 01:08:18,290 +Well first thing is if +you're asking me to go fetch + +1513 +01:08:18,290 --> 01:08:19,830 +the background image data, + +1514 +01:08:19,830 --> 01:08:24,390 +I'm gonna set my current +backgroundImage to nil. + +1515 +01:08:24,390 --> 01:08:26,560 +So I'm in the process of +going out in the internet + +1516 +01:08:26,560 --> 01:08:27,860 +and getting something. + +1517 +01:08:27,860 --> 01:08:29,230 +That might take quite awhile. + +1518 +01:08:29,230 --> 01:08:31,910 +Maybe it's a big image or +maybe the server that it's on + +1519 +01:08:31,910 --> 01:08:33,010 +is really slow. + +1520 +01:08:33,010 --> 01:08:35,140 +So in the meantime, I'm gonna +clear the backgroundImage + +1521 +01:08:35,140 --> 01:08:37,500 +just to let you know, +yeah I know you changed + +1522 +01:08:37,500 --> 01:08:39,257 +the backgroundImage, you +dropped something on me. + +1523 +01:08:39,257 --> 01:08:40,633 +And I'm working on it. + +1524 +01:08:41,700 --> 01:08:44,140 +Really what we'd like +to do is provide some UI + +1525 +01:08:45,030 --> 01:08:47,030 +to give some feedback +that we're working on it. + +1526 +01:08:47,030 --> 01:08:50,530 +Maybe we will actually +demo that, time permitting. + +1527 +01:08:50,530 --> 01:08:53,010 +But we definitely need +to give some feedback + +1528 +01:08:53,010 --> 01:08:56,100 +that, "Yeah, we saw that drop +and we're working on it." + +1529 +01:08:56,100 --> 01:08:59,960 +So that's that, and then +if the URL that was dropped + +1530 +01:08:59,960 --> 01:09:04,790 +which is this emojiArt.backgroundURL now, + +1531 +01:09:04,790 --> 01:09:08,090 +if that's nil then there's +no need to go fetch anything. + +1532 +01:09:08,090 --> 01:09:10,500 +So I'm gonna put this if let url around it + +1533 +01:09:10,500 --> 01:09:12,280 +so that I'm only doing any fetching + +1534 +01:09:12,280 --> 01:09:14,090 +on the internet (chuckles) +if I've actually + +1535 +01:09:14,090 --> 01:09:16,290 +got a URL to go look for. + +1536 +01:09:16,290 --> 01:09:20,810 +So fetching the information +from a URL is really simple. + +1537 +01:09:20,810 --> 01:09:23,540 +There is a more sophisticated +mechanism for doing this. + +1538 +01:09:23,540 --> 01:09:24,800 +We're gonna do the simplest one + +1539 +01:09:24,800 --> 01:09:26,390 +'cause we were only really focused + +1540 +01:09:26,390 --> 01:09:29,490 +on the asynchronous programming +that's going on here. + +1541 +01:09:29,490 --> 01:09:31,740 +But if you were really +gonna be downloading stuff + +1542 +01:09:31,740 --> 01:09:35,060 +from the internet, you +would use URLSession. + +1543 +01:09:35,060 --> 01:09:38,100 +And I'm not gonna talk about +the whole URLSession API + +1544 +01:09:38,100 --> 01:09:40,360 +but essentially it's +just a closure-based API. + +1545 +01:09:40,360 --> 01:09:43,410 +You pass closures to it, it +goes and downloads stuff. + +1546 +01:09:43,410 --> 01:09:46,160 +It calls your closures when +the downloads come back + +1547 +01:09:46,160 --> 01:09:49,680 +or it'll call other +closures when errors occur. + +1548 +01:09:49,680 --> 01:09:51,840 +But a simple way to +fetch data is just to say + +1549 +01:09:51,840 --> 01:09:56,840 +if let imageData equal, +try getting the data + +1550 +01:09:56,860 --> 01:09:59,103 +from the contents of that URL. + +1551 +01:10:00,220 --> 01:10:03,480 +This Data is just an object, a struct, + +1552 +01:10:03,480 --> 01:10:06,210 +and it has initializer +where you give it a URL + +1553 +01:10:06,210 --> 01:10:07,940 +and it will go out on the internet + +1554 +01:10:07,940 --> 01:10:11,200 +and get the data at +that URL and return it. + +1555 +01:10:11,200 --> 01:10:14,210 +This can encounter all kinds of errors: + +1556 +01:10:14,210 --> 01:10:17,670 +internet timeouts, all +kinds of things happening. + +1557 +01:10:17,670 --> 01:10:19,730 +So that's why we have to do this try. + +1558 +01:10:19,730 --> 01:10:21,550 +And in next week's reading assignment, + +1559 +01:10:21,550 --> 01:10:24,030 +you're gonna learn about +try and thrown errors. + +1560 +01:10:24,030 --> 01:10:26,080 +I'm not gonna talk about it today, + +1561 +01:10:26,080 --> 01:10:28,840 +but just know that there +are some constructors + +1562 +01:10:28,840 --> 01:10:31,170 +that you call and some +functions that you call + +1563 +01:10:31,170 --> 01:10:32,850 +that have to be try-ed. + +1564 +01:10:32,850 --> 01:10:35,270 +And when you do this try +with a question mark, + +1565 +01:10:35,270 --> 01:10:38,500 +it means try this and +if it fails, (chuckles) + +1566 +01:10:38,500 --> 01:10:40,880 +network timeout, +whatever, just return nil. + +1567 +01:10:40,880 --> 01:10:42,390 +And since I'm doing if let, + +1568 +01:10:42,390 --> 01:10:45,173 +this in here won't get +executed if this fails. + +1569 +01:10:46,450 --> 01:10:49,720 +Now a huge problem with this line of code. + +1570 +01:10:49,720 --> 01:10:53,740 +This could take 10 seconds or two minutes + +1571 +01:10:53,740 --> 01:10:55,610 +depending on what the timeout is. + +1572 +01:10:55,610 --> 01:10:57,640 +Certainly probably gonna +take at least a half a second + +1573 +01:10:57,640 --> 01:11:00,790 +or a second, and during +that time my whole app + +1574 +01:11:00,790 --> 01:11:04,180 +is stuck waiting for this line +of code (chuckles) to execute + +1575 +01:11:04,180 --> 01:11:06,410 +and that is the rub. + +1576 +01:11:06,410 --> 01:11:08,480 +That we can never allow to happen. + +1577 +01:11:08,480 --> 01:11:12,550 +We can never call a function +like this that blocks our code + +1578 +01:11:12,550 --> 01:11:13,640 +waiting for it to return + +1579 +01:11:13,640 --> 01:11:15,840 +because it can take seconds to do this. + +1580 +01:11:15,840 --> 01:11:19,820 +Never call that in the +same thread of execution + +1581 +01:11:19,820 --> 01:11:22,750 +as all of our UIs +happening, otherwise our app + +1582 +01:11:22,750 --> 01:11:25,200 +is going to freeze and the +user's gonna be clicking + +1583 +01:11:25,200 --> 01:11:27,070 +and typing and trying +to drag a new thing in, + +1584 +01:11:27,070 --> 01:11:29,760 +and, "I, I didn't want that +URL, it's taking too long." + +1585 +01:11:29,760 --> 01:11:30,593 +No, they can't do anything. + +1586 +01:11:30,593 --> 01:11:33,340 +Our app, they can't even +scroll their emoji at the top. + +1587 +01:11:33,340 --> 01:11:36,130 +It's all frozen because our +app is sitting right here + +1588 +01:11:36,130 --> 01:11:39,323 +on this line of code for 10 +seconds, 15 seconds, whatever. + +1589 +01:11:40,460 --> 01:11:41,870 +So how do we get around that? + +1590 +01:11:41,870 --> 01:11:43,670 +We use what we talked about in the slides, + +1591 +01:11:43,670 --> 01:11:45,240 +the dispatch mechanism. + +1592 +01:11:45,240 --> 01:11:50,240 +So I'm going to dispatch +this code to a global queue. + +1593 +01:11:50,377 --> 01:11:52,670 +And the quality of service I want here + +1594 +01:11:52,670 --> 01:11:54,890 +is called userInitiated. + +1595 +01:11:54,890 --> 01:11:57,810 +Remember there's these +different qualities of service. + +1596 +01:11:57,810 --> 01:12:00,090 +I want userInitiated because +that's exactly what happened. + +1597 +01:12:00,090 --> 01:12:02,450 +The user initiated a request here. + +1598 +01:12:02,450 --> 01:12:04,940 +And so that right there, +that that you've seen, + +1599 +01:12:04,940 --> 01:12:08,723 +this DispatchQueue.global, +that gives me a global queue, + +1600 +01:12:08,723 --> 01:12:11,280 +a queue that executes its +code off the main queue, + +1601 +01:12:11,280 --> 01:12:12,730 +not where the UI is. + +1602 +01:12:12,730 --> 01:12:15,410 +And I'm going to asynchronously ask it + +1603 +01:12:15,410 --> 01:12:17,480 +to perform this function. + +1604 +01:12:17,480 --> 01:12:19,500 +This function takes no +argument, return no arguments. + +1605 +01:12:19,500 --> 01:12:23,450 +And I'm just gonna ask it +please perform this function + +1606 +01:12:23,450 --> 01:12:25,780 +off on this queue, whatever it is, + +1607 +01:12:25,780 --> 01:12:30,010 +and I'll have nothing else +to do with you, just do it. + +1608 +01:12:30,010 --> 01:12:32,393 +So I'm gonna put this inside here now. + +1609 +01:12:33,257 --> 01:12:35,490 +And this is great because +now this is blocking still, + +1610 +01:12:35,490 --> 01:12:39,160 +still taking five seconds, but +off on some background queue, + +1611 +01:12:39,160 --> 01:12:41,147 +not in the same queue where all the code + +1612 +01:12:41,147 --> 01:12:43,633 +for our UI is being executed. + +1613 +01:12:44,800 --> 01:12:45,633 +So that's great. + +1614 +01:12:45,633 --> 01:12:47,530 +Now the imageData comes back, let's say. + +1615 +01:12:47,530 --> 01:12:48,900 +You know, let's say there was no error + +1616 +01:12:48,900 --> 01:12:51,400 +and so this try, that +it didn't return nil. + +1617 +01:12:51,400 --> 01:12:53,190 +And now I've got the imageData! + +1618 +01:12:53,190 --> 01:12:55,390 +It's JPEG data or PNG data + +1619 +01:12:55,390 --> 01:12:58,020 +or some kind of data from the internet. + +1620 +01:12:58,020 --> 01:13:00,420 +And I need to turn it into a UIImage + +1621 +01:13:00,420 --> 01:13:01,730 +'cause that's what I'm trying to do here + +1622 +01:13:01,730 --> 01:13:03,650 +is make this UIImage here. + +1623 +01:13:03,650 --> 01:13:06,100 +And luckily UIImage has +a great way to do that. + +1624 +01:13:06,100 --> 01:13:10,820 +I could just say +backgroundImage equals UIImage + +1625 +01:13:10,820 --> 01:13:12,313 +with this Data. + +1626 +01:13:13,240 --> 01:13:15,790 +This line of code has a +humongous problem, okay. + +1627 +01:13:15,790 --> 01:13:18,260 +Just like this line of code +was a problem that it blocked + +1628 +01:13:18,260 --> 01:13:20,490 +and we fixed that by putting +on a background queue. + +1629 +01:13:20,490 --> 01:13:23,240 +This one has a huge +problem which is that this + +1630 +01:13:23,240 --> 01:13:25,360 +is going to set this backgroundImage + +1631 +01:13:25,360 --> 01:13:28,670 +which is gonna cause this +publishing to happen up here, + +1632 +01:13:28,670 --> 01:13:32,760 +which is gonna cause our +View over here to redraw + +1633 +01:13:32,760 --> 01:13:36,010 +which means UI is going to be happening + +1634 +01:13:36,010 --> 01:13:38,940 +on a background thread. + +1635 +01:13:38,940 --> 01:13:41,177 +And that is never allowed, that is, + +1636 +01:13:41,177 --> 01:13:43,030 +and in fact when you do that, + +1637 +01:13:43,030 --> 01:13:45,140 +your app is gonna start behaving funny, + +1638 +01:13:45,140 --> 01:13:47,810 +might possibly even crash. + +1639 +01:13:47,810 --> 01:13:50,210 +And you're gonna get little +purple warnings up here + +1640 +01:13:50,210 --> 01:13:52,287 +when you're running your +app in Xcode that says, + +1641 +01:13:52,287 --> 01:13:54,720 +"Ah, you drew something +outside the main queue!" + +1642 +01:13:54,720 --> 01:13:56,890 +So we can never do something like this, + +1643 +01:13:56,890 --> 01:14:00,330 +a line of code that would +cause drawing to happen + +1644 +01:14:00,330 --> 01:14:03,260 +on non main threads. + +1645 +01:14:03,260 --> 01:14:05,410 +So how do we put this +back on the main thread? + +1646 +01:14:05,410 --> 01:14:07,810 +We do it the exact same +way that we put this code + +1647 +01:14:07,810 --> 01:14:10,360 +on this thread originally. + +1648 +01:14:10,360 --> 01:14:12,060 +But we're gonna put it on instead of + +1649 +01:14:12,060 --> 01:14:15,500 +a background userInitiated +quality of service thread, + +1650 +01:14:15,500 --> 01:14:19,110 +we're gonna put this DispatchQueue.main. + +1651 +01:14:19,110 --> 01:14:20,210 +So it'll be the same thing. + +1652 +01:14:20,210 --> 01:14:24,810 +I'm gonna asynchronously post +a little function closure + +1653 +01:14:24,810 --> 01:14:27,530 +to the main queue and say go do this. + +1654 +01:14:27,530 --> 01:14:30,370 +Now posting something asynchronously + +1655 +01:14:30,370 --> 01:14:32,240 +basically means it gets in the queue, + +1656 +01:14:32,240 --> 01:14:34,480 +that's why we call these queues, to run. + +1657 +01:14:34,480 --> 01:14:36,300 +And there might be other threads + +1658 +01:14:36,300 --> 01:14:39,600 +that are posting these +little function snippets + +1659 +01:14:39,600 --> 01:14:41,172 +to run on the main queue. + +1660 +01:14:41,172 --> 01:14:42,380 +And so this guy might have to get in line + +1661 +01:14:42,380 --> 01:14:43,710 +if something else is happening. + +1662 +01:14:43,710 --> 01:14:45,830 +In fact one of those might +be executing right now. + +1663 +01:14:45,830 --> 01:14:49,120 +The user just touched on +something or scrolled their emojis + +1664 +01:14:49,120 --> 01:14:51,720 +at the top, so the main queue is busy. + +1665 +01:14:51,720 --> 01:14:53,810 +But when it's settled down, it's not busy, + +1666 +01:14:53,810 --> 01:14:56,280 +it'll start attending +to its queue of requests + +1667 +01:14:56,280 --> 01:14:58,723 +and eventually it will execute this. + +1668 +01:14:59,610 --> 01:15:02,220 +This really is all there is + +1669 +01:15:02,220 --> 01:15:03,750 +to this multithreaded programming + +1670 +01:15:03,750 --> 01:15:08,750 +and it looks really simple, and it is. + +1671 +01:15:09,400 --> 01:15:10,890 +But it can get you in a little trouble + +1672 +01:15:10,890 --> 01:15:12,833 +as I will explain in just a minute. + +1673 +01:15:14,280 --> 01:15:16,210 +But this should be enough, right. + +1674 +01:15:16,210 --> 01:15:17,660 +We did what we said we were gonna do + +1675 +01:15:17,660 --> 01:15:19,284 +in this fetchBackgroundImageData + +1676 +01:15:19,284 --> 01:15:21,930 +is we are setting the +backgroundImage to the UIImage + +1677 +01:15:21,930 --> 01:15:23,040 +from fetching that data. + +1678 +01:15:23,040 --> 01:15:24,340 +So let's see it in action. + +1679 +01:15:27,880 --> 01:15:29,687 +All right, here we go, pick this guy up. + +1680 +01:15:29,687 --> 01:15:32,380 +And we drag him, he's +turning green, that's good, + +1681 +01:15:32,380 --> 01:15:34,820 +go over here and drop! + +1682 +01:15:34,820 --> 01:15:37,870 +Ah, whoa, it worked! + +1683 +01:15:37,870 --> 01:15:39,440 +Now there was a slight delay. + +1684 +01:15:39,440 --> 01:15:40,310 +I don't know if you noticed it. + +1685 +01:15:40,310 --> 01:15:42,620 +We dropped it and it took +about a half a second + +1686 +01:15:42,620 --> 01:15:44,340 +to draw this image. + +1687 +01:15:44,340 --> 01:15:46,640 +And during that half second, +it was just going over + +1688 +01:15:46,640 --> 01:15:48,930 +the internet to whatever +website this is on + +1689 +01:15:48,930 --> 01:15:51,043 +and pulling that image over. + +1690 +01:15:52,040 --> 01:15:53,410 +Let's talk a little bit though + +1691 +01:15:53,410 --> 01:15:56,060 +about these asynchronous things + +1692 +01:15:56,060 --> 01:15:57,940 +and why it's not always as straightforward + +1693 +01:15:57,940 --> 01:15:59,220 +as you might think. + +1694 +01:15:59,220 --> 01:16:02,430 +I'm gonna describe a +scenario that goes on here + +1695 +01:16:02,430 --> 01:16:05,693 +and you can see why this code +is actually not quite right. + +1696 +01:16:06,640 --> 01:16:09,530 +Let's say that I drag and drop an image + +1697 +01:16:09,530 --> 01:16:13,740 +from a really slow server and +it's gonna take 15 seconds. + +1698 +01:16:13,740 --> 01:16:15,290 +And after about three or four seconds, + +1699 +01:16:15,290 --> 01:16:16,977 +as the user, I'm like, +"Ah, I'm tired of waiting + +1700 +01:16:16,977 --> 01:16:20,090 +"for that image," and you go +to another one, a fast server, + +1701 +01:16:20,090 --> 01:16:21,890 +and you drag a new thing in. + +1702 +01:16:21,890 --> 01:16:24,070 +And of course, the fast server +gives it to your right away, + +1703 +01:16:24,070 --> 01:16:25,227 +and boop, you display it. + +1704 +01:16:25,227 --> 01:16:28,330 +And so now it's displaying +and maybe you go on + +1705 +01:16:28,330 --> 01:16:30,840 +and you're like, "Ah, I'm +gonna add some emoji to it," + +1706 +01:16:30,840 --> 01:16:33,830 +and then the other one finally returns. + +1707 +01:16:33,830 --> 01:16:37,790 +And what's it gonna do, boom, +reset your background image. + +1708 +01:16:37,790 --> 01:16:40,150 +So that is really unexpected for the user. + +1709 +01:16:40,150 --> 01:16:41,500 +I dragged something in. + +1710 +01:16:41,500 --> 01:16:43,480 +I think it failed 'cause it took too long. + +1711 +01:16:43,480 --> 01:16:44,610 +So I dragged something else in. + +1712 +01:16:44,610 --> 01:16:47,140 +It was quick, it got there, +and then 10 seconds later, + +1713 +01:16:47,140 --> 01:16:49,000 +boom, the old thing comes in. + +1714 +01:16:49,000 --> 01:16:52,010 +So that we never would want to happen. + +1715 +01:16:52,010 --> 01:16:54,520 +Now it's easily protectable against, + +1716 +01:16:54,520 --> 01:16:56,270 +which is just when I go back here + +1717 +01:16:56,270 --> 01:16:58,400 +to set this backgroundImage, +I'm gonna make sure + +1718 +01:16:58,400 --> 01:17:02,103 +that this Data that I got +is for the background URL + +1719 +01:17:02,103 --> 01:17:03,440 +that the user still wants. + +1720 +01:17:03,440 --> 01:17:05,800 +We can just do it in +here and say if the URL + +1721 +01:17:06,729 --> 01:17:08,870 +that I just fetched, +right, that's this URL + +1722 +01:17:08,870 --> 01:17:10,820 +that I got right here. + +1723 +01:17:10,820 --> 01:17:13,747 +If it equals the EmojiArt's + +1724 +01:17:15,790 --> 01:17:19,750 +backgroundURL, then I'll +go ahead and load it up. + +1725 +01:17:19,750 --> 01:17:22,000 +But if it's some other URL that I got + +1726 +01:17:22,000 --> 01:17:24,750 +15 seconds ago, (chuckles) +then I'm just gonna do nothing. + +1727 +01:17:24,750 --> 01:17:25,740 +I'm gonna ignore it. + +1728 +01:17:25,740 --> 01:17:27,570 +I still fetched it, it still arrived, + +1729 +01:17:27,570 --> 01:17:30,180 +but I'm not gonna waste +my time making an image + +1730 +01:17:30,180 --> 01:17:33,200 +and certainly not gonna blast +it in front of the user. + +1731 +01:17:33,200 --> 01:17:36,343 +So this kind of minor thing right here, + +1732 +01:17:36,343 --> 01:17:38,210 +it's the kind of thing you have to be able + +1733 +01:17:38,210 --> 01:17:40,400 +to protect against and be careful about + +1734 +01:17:40,400 --> 01:17:42,260 +when you have this +asynchronous programming. + +1735 +01:17:42,260 --> 01:17:44,640 +You can't just blindly +be posting back and forth + +1736 +01:17:44,640 --> 01:17:47,460 +and not thinking about +what if things like this + +1737 +01:17:47,460 --> 01:17:51,053 +take a very long time and then, +it's another one comes by. + +1738 +01:17:52,040 --> 01:17:54,840 +Make sure that didn't break +anything, I'm sure it won't. + +1739 +01:17:56,900 --> 01:17:58,470 +Drag our image in here. + +1740 +01:17:58,470 --> 01:18:00,850 +Oop, there it is, working great. + +1741 +01:18:00,850 --> 01:18:02,400 +Now that we have our image working here, + +1742 +01:18:02,400 --> 01:18:04,780 +let's make it so we can pick these up + +1743 +01:18:04,780 --> 01:18:07,940 +and drag them in here, +drag our emojis in here. + +1744 +01:18:07,940 --> 01:18:12,840 +So that's both making it +so we can drop little texts + +1745 +01:18:12,840 --> 01:18:16,080 +on our View here, but +also we got to make it + +1746 +01:18:16,080 --> 01:18:17,700 +so these things are draggable + +1747 +01:18:17,700 --> 01:18:20,710 +so that we're doing drag +and drop with this one. + +1748 +01:18:20,710 --> 01:18:22,640 +So let's do the drop side of it first + +1749 +01:18:22,640 --> 01:18:24,290 +because we already know how to drop + +1750 +01:18:24,290 --> 01:18:28,433 +and it's actually really easy +to drop the emoji as well. + +1751 +01:18:30,540 --> 01:18:33,340 +Over here in our View, so here's onDrop. + +1752 +01:18:33,340 --> 01:18:35,360 +Right now onDrop just +lets you drop the image + +1753 +01:18:35,360 --> 01:18:36,230 +for the background. + +1754 +01:18:36,230 --> 01:18:39,870 +Now I'm gonna make it so that +onDrop also can drop a Text + +1755 +01:18:39,870 --> 01:18:42,430 +'cause our emojis are just +little snippets of Text. + +1756 +01:18:42,430 --> 01:18:45,600 +So public.text is the URI for Text. + +1757 +01:18:45,600 --> 01:18:48,520 +Now in this case, I do need the location. + +1758 +01:18:48,520 --> 01:18:50,570 +If you drop an emoji, I need the, + +1759 +01:18:50,570 --> 01:18:53,570 +let's get rid of this +URL printing right there. + +1760 +01:18:53,570 --> 01:18:55,960 +In this case, I do need the location. + +1761 +01:18:55,960 --> 01:18:56,880 +So we're gonna have to do it. + +1762 +01:18:56,880 --> 01:19:00,300 +Now the location that's +provided here when we drop, + +1763 +01:19:00,300 --> 01:19:02,000 +I think it's actually a bug. + +1764 +01:19:02,000 --> 01:19:05,000 +But it's currently in +global coordinate systems, + +1765 +01:19:05,000 --> 01:19:08,290 +the coordinate system of the +entire device, basically. + +1766 +01:19:08,290 --> 01:19:11,730 +Not the little coordinate +system of our little, + +1767 +01:19:11,730 --> 01:19:14,160 +you know, Color here with +an Image in front of it, + +1768 +01:19:14,160 --> 01:19:15,410 +which, that's bad for us. + +1769 +01:19:15,410 --> 01:19:17,540 +We need to convert it to do that. + +1770 +01:19:17,540 --> 01:19:21,970 +So I provided a little +extension to GeometryReader + +1771 +01:19:21,970 --> 01:19:24,800 +right here, GeometryProxy, +that can convert + +1772 +01:19:24,800 --> 01:19:26,860 +from some coordinate +space and we're gonna use + +1773 +01:19:26,860 --> 01:19:29,800 +this little function to +convert this location + +1774 +01:19:29,800 --> 01:19:32,380 +that we're given here +from global coordinates + +1775 +01:19:32,380 --> 01:19:34,520 +to our View's coordinate system. + +1776 +01:19:34,520 --> 01:19:35,610 +Pretty straightforward, +I'm just gonna create + +1777 +01:19:35,610 --> 01:19:37,470 +a little var here location. + +1778 +01:19:37,470 --> 01:19:40,220 +And I'm gonna use that GeometryProxy thing + +1779 +01:19:40,220 --> 01:19:43,540 +that I just showed you +to convert that location + +1780 +01:19:43,540 --> 01:19:46,500 +that we're given from the global. + +1781 +01:19:46,500 --> 01:19:50,150 +So this is converting this +location from global coordinates. + +1782 +01:19:50,150 --> 01:19:52,000 +Now there's another +conversion I have to do. + +1783 +01:19:52,000 --> 01:19:55,400 +This location is in iOS coordinate system. + +1784 +01:19:55,400 --> 01:19:57,500 +Remember the iOS coordinate system? + +1785 +01:19:57,500 --> 01:20:00,030 +It's the upper left is (0, 0). + +1786 +01:20:00,030 --> 01:20:03,610 +My EmojiArt, I'm gonna have its X and Y + +1787 +01:20:03,610 --> 01:20:06,413 +be offset from the center. + +1788 +01:20:07,360 --> 01:20:10,440 +Not just to be different, but +I actually think it's easier + +1789 +01:20:10,440 --> 01:20:12,130 +to store it this way. + +1790 +01:20:12,130 --> 01:20:15,310 +And so we need to convert +from iOS coordinates, + +1791 +01:20:15,310 --> 01:20:18,190 +zero, zero in the upper +left, to this coordinates, + +1792 +01:20:18,190 --> 01:20:19,593 +zero, zero in the middle. + +1793 +01:20:21,500 --> 01:20:25,513 +Our location equals a CGPoint + +1794 +01:20:26,900 --> 01:20:29,810 +and X is the location you +gave us in the iOS coordinates + +1795 +01:20:29,810 --> 01:20:33,380 +but minus the GeometryReader's + +1796 +01:20:33,380 --> 01:20:35,650 +proxy size.width divided by two, + +1797 +01:20:35,650 --> 01:20:38,700 +and the Y is the location +you gave us in the Y + +1798 +01:20:38,700 --> 01:20:43,700 +minus the geometry's +size.height divide by two. + +1799 +01:20:45,240 --> 01:20:47,960 +Now here I'm using my +GeometryReader both here + +1800 +01:20:47,960 --> 01:20:50,370 +to convert that and my GeometryReader here + +1801 +01:20:50,370 --> 01:20:51,930 +to convert from global. + +1802 +01:20:51,930 --> 01:20:54,720 +So I clearly need my GeometryReader here. + +1803 +01:20:54,720 --> 01:20:59,093 +So let's put GeometryReader around this. + +1804 +01:21:00,620 --> 01:21:02,170 +Then the last thing we need to do + +1805 +01:21:02,170 --> 01:21:05,660 +is have this drop handler +not only take the providers + +1806 +01:21:05,660 --> 01:21:09,060 +but it also needs to take the locations. + +1807 +01:21:09,060 --> 01:21:11,810 +So let's enhance this +drop to take the location, + +1808 +01:21:11,810 --> 01:21:14,263 +comma at location which is a CGPoint. + +1809 +01:21:15,960 --> 01:21:17,700 +Now in here, right now I'm looking + +1810 +01:21:17,700 --> 01:21:19,350 +for the first object to be a URL. + +1811 +01:21:20,270 --> 01:21:24,370 +So if I don't find that, if not found + +1812 +01:21:24,370 --> 01:21:28,550 +then I'm gonna go and see if +found equals the providers + +1813 +01:21:28,550 --> 01:21:33,550 +load up objects of type String.self. + +1814 +01:21:34,110 --> 01:21:37,530 +So here I was loading the +first object ofType URL, + +1815 +01:21:37,530 --> 01:21:40,530 +here I'm loading all +objects ofType String. + +1816 +01:21:40,530 --> 01:21:43,730 +And that has a little argument here + +1817 +01:21:43,730 --> 01:21:47,140 +which is string in. + +1818 +01:21:47,140 --> 01:21:48,890 +And this is gonna call +this little function + +1819 +01:21:48,890 --> 01:21:51,257 +for all the strings +that are found in there. + +1820 +01:21:51,257 --> 01:21:53,160 +And I'm gonna assume all +my strings are emojis. + +1821 +01:21:53,160 --> 01:21:54,780 +Now this does mean I could drag + +1822 +01:21:54,780 --> 01:21:57,790 +a non-emoji string (chuckles) on and that, + +1823 +01:21:57,790 --> 01:21:59,643 +it's going to work, but that's okay. + +1824 +01:22:00,650 --> 01:22:02,260 +So here what do I want to do? + +1825 +01:22:02,260 --> 01:22:05,120 +If this happens, I'm just +gonna use my intent right here, + +1826 +01:22:05,120 --> 01:22:09,610 +this document.addEmoji and +the emoji is the String + +1827 +01:22:09,610 --> 01:22:12,090 +that was dropped on me and +the point is the location + +1828 +01:22:12,090 --> 01:22:13,477 +that it was dropped at. + +1829 +01:22:13,477 --> 01:22:16,510 +And the size is the defaultEmojiSize. + +1830 +01:22:16,510 --> 01:22:19,010 +So we're gonna have +emojis that are dropped + +1831 +01:22:19,010 --> 01:22:22,920 +be this defaultEmojiSize, +the same size we used + +1832 +01:22:22,920 --> 01:22:24,733 +with our ScrollView at the top. + +1833 +01:22:25,760 --> 01:22:29,242 +Now this is complaining +'cause let found is a let. + +1834 +01:22:29,242 --> 01:22:31,010 +Let's just make it be a var +'cause now we're searching + +1835 +01:22:31,010 --> 01:22:34,980 +for two things here, and +this is all we needed to do + +1836 +01:22:34,980 --> 01:22:36,140 +on the drop side. + +1837 +01:22:36,140 --> 01:22:39,010 +We got the location and +we're just checking for them + +1838 +01:22:39,010 --> 01:22:41,300 +and adding them using this Intent, right. + +1839 +01:22:41,300 --> 01:22:42,800 +Remember, everyone remember this Intent + +1840 +01:22:42,800 --> 01:22:45,260 +that we added over here, AddEmoji. + +1841 +01:22:45,260 --> 01:22:46,370 +The last thing we want to do is be able + +1842 +01:22:46,370 --> 01:22:49,530 +to drag our emojis out. + +1843 +01:22:49,530 --> 01:22:52,080 +Here are the emojis +that are in the palette. + +1844 +01:22:52,080 --> 01:22:53,630 +To do this is incredibly easy. + +1845 +01:22:53,630 --> 01:22:55,850 +We're just gonna say onDrag. + +1846 +01:22:55,850 --> 01:22:58,890 +Now onDrag takes a function. + +1847 +01:22:58,890 --> 01:23:03,040 +And this function just needs +to return the things to drag. + +1848 +01:23:03,040 --> 01:23:04,890 +And these need to be NSItemProviders. + +1849 +01:23:06,100 --> 01:23:08,850 +Remember NSItemProviders +are what these providers are + +1850 +01:23:08,850 --> 01:23:10,340 +down here when we drop. + +1851 +01:23:10,340 --> 01:23:12,060 +So there needs to be a provider. + +1852 +01:23:12,060 --> 01:23:14,210 +So I need to create a +provider that essentially + +1853 +01:23:14,210 --> 01:23:16,823 +provides this emoji right here. + +1854 +01:23:17,756 --> 01:23:21,460 +And NSItemProvider +almost has the one I want + +1855 +01:23:21,460 --> 01:23:24,600 +and something for that, +object it's called, + +1856 +01:23:24,600 --> 01:23:27,550 +on NSItemProvider object +and it will take this object + +1857 +01:23:27,550 --> 01:23:30,440 +and for certain known types +like Strings and Images, + +1858 +01:23:30,440 --> 01:23:33,200 +it will create an ItemProvider here. + +1859 +01:23:33,200 --> 01:23:37,210 +Unfortunately, this is +old Objective-C world code + +1860 +01:23:37,210 --> 01:23:41,010 +imported into SwiftUI and +so we have to put this + +1861 +01:23:41,010 --> 01:23:43,880 +as NSString on here. + +1862 +01:23:43,880 --> 01:23:46,150 +This is because +ItemProviders will only take + +1863 +01:23:46,150 --> 01:23:47,560 +these old NS things. + +1864 +01:23:47,560 --> 01:23:50,350 +You see it starts with +NS, this starts with NS. + +1865 +01:23:50,350 --> 01:23:52,210 +Not gonna talk about as right now. + +1866 +01:23:52,210 --> 01:23:54,580 +We'll talk about it later, what it means, + +1867 +01:23:54,580 --> 01:23:56,400 +but it essentially converts this emoji + +1868 +01:23:56,400 --> 01:23:59,050 +which is a type String, these are Strings, + +1869 +01:23:59,050 --> 01:24:03,500 +into this NS world so that +NSItemProvider can do it. + +1870 +01:24:03,500 --> 01:24:06,050 +And of course we don't need +return there, actually. + +1871 +01:24:07,440 --> 01:24:08,930 +So let's see if this works. + +1872 +01:24:08,930 --> 01:24:12,220 +We got our drag up here, +we got our drop down here. + +1873 +01:24:12,220 --> 01:24:13,053 +Let's see if we can do it. + +1874 +01:24:13,053 --> 01:24:14,390 +Let's start with this background, + +1875 +01:24:14,390 --> 01:24:15,910 +make sure that didn't get broken. + +1876 +01:24:15,910 --> 01:24:19,413 +Oh, works fine, and let's +maybe drag earth down here. + +1877 +01:24:19,413 --> 01:24:21,600 +Ooh, I see a green plus! + +1878 +01:24:21,600 --> 01:24:23,430 +Oh, it didn't display. + +1879 +01:24:23,430 --> 01:24:26,080 +So our drag and drop appears to be working + +1880 +01:24:26,080 --> 01:24:27,890 +'cause we got the green plus. + +1881 +01:24:27,890 --> 01:24:31,760 +But we don't actually draw +our emojis that are dropped + +1882 +01:24:31,760 --> 01:24:34,868 +anywhere in our UI here. + +1883 +01:24:34,868 --> 01:24:37,250 +We draw our palettes up here, + +1884 +01:24:37,250 --> 01:24:38,550 +but we don't actually draw (chuckles) + +1885 +01:24:38,550 --> 01:24:40,360 +the emojis that are dropped. + +1886 +01:24:40,360 --> 01:24:45,180 +We just need to put that on top +of this white overlaid image + +1887 +01:24:45,180 --> 01:24:47,430 +so I'm gonna make a ZStack, +stack these two things + +1888 +01:24:47,430 --> 01:24:49,220 +on top of each other, this guy. + +1889 +01:24:49,220 --> 01:24:51,860 +And this second thing that I'm +gonna put in the ZStack here + +1890 +01:24:51,860 --> 01:24:56,860 +is just ForEach of all of the Emojis + +1891 +01:24:58,290 --> 01:25:00,223 +in my document. + +1892 +01:25:02,200 --> 01:25:04,030 +And for each one of these +things, I'm going to have + +1893 +01:25:04,030 --> 01:25:06,750 +to make a View to draw it. + +1894 +01:25:06,750 --> 01:25:09,600 +Now I don't currently have any var + +1895 +01:25:09,600 --> 01:25:12,150 +that gives me the Emojis in the document. + +1896 +01:25:12,150 --> 01:25:14,650 +And if you look over in my document, + +1897 +01:25:14,650 --> 01:25:17,730 +my Model is private so I +can't look at the emojiArt + +1898 +01:25:17,730 --> 01:25:21,860 +so I'm gonna need another +var here which is emojis + +1899 +01:25:21,860 --> 01:25:26,280 +and it's gonna be of type +Array of EmojiArt.Emoji. + +1900 +01:25:26,280 --> 01:25:30,700 +And this thing is just going +to return my emojiArt.emojis + +1901 +01:25:30,700 --> 01:25:33,718 +since this is a get only computed var. + +1902 +01:25:33,718 --> 01:25:36,300 +This is a read-only version +of this emojiArts, okay. + +1903 +01:25:36,300 --> 01:25:39,550 +That's kind of exactly what +my ViewModel here wants to do + +1904 +01:25:39,550 --> 01:25:42,750 +is provide a read-only access to the Model + +1905 +01:25:42,750 --> 01:25:47,123 +since it provides immutable +access via its Intent functions. + +1906 +01:25:48,630 --> 01:25:51,820 +So inside here, these +emojis are Identifiable. + +1907 +01:25:51,820 --> 01:25:54,580 +That's great, we made emoji Identifiable. + +1908 +01:25:54,580 --> 01:25:57,760 +And to display them, it's +just Text of the emoji. + +1909 +01:25:57,760 --> 01:25:59,077 +That's all we need to do. + +1910 +01:25:59,077 --> 01:26:03,290 +The only thing about that +is we want to set the font + +1911 +01:26:03,290 --> 01:26:07,560 +to be the size and we want to +set the position of this thing + +1912 +01:26:07,560 --> 01:26:09,900 +to be wherever the +position is in the Model. + +1913 +01:26:09,900 --> 01:26:11,550 +So we're gonna have to +do both of those things. + +1914 +01:26:11,550 --> 01:26:13,240 +So I'm gonna create little +functions to do that. + +1915 +01:26:13,240 --> 01:26:18,240 +So let's have the font return +self.font for this Emoji + +1916 +01:26:18,580 --> 01:26:22,440 +and then we'll have the +position return to self.position + +1917 +01:26:22,440 --> 01:26:24,239 +for this emoji. + +1918 +01:26:24,239 --> 01:26:26,970 +And for that, because of +the coordinate system space + +1919 +01:26:26,970 --> 01:26:29,110 +between (0, 0) in the +middle or upper left, + +1920 +01:26:29,110 --> 01:26:34,110 +I'm gonna have to pass this +geometry.size in there. + +1921 +01:26:34,270 --> 01:26:36,220 +So let's make these two little functions + +1922 +01:26:36,220 --> 01:26:39,510 +and then I think we'll be +done here, font and position, + +1923 +01:26:39,510 --> 01:26:42,420 +private func font + +1924 +01:26:43,610 --> 01:26:46,387 +for emoji, EmojiArt.Emoji. + +1925 +01:26:47,956 --> 01:26:49,600 +These are gonna return a Font. + +1926 +01:26:49,600 --> 01:26:51,530 +And this one's pretty simple to do. + +1927 +01:26:51,530 --> 01:26:55,407 +We're just going to do Font.system size. + +1928 +01:26:55,407 --> 01:26:57,100 +And we need to get the size. + +1929 +01:26:57,100 --> 01:27:01,810 +Now this size is actually +in the Emoji as size. + +1930 +01:27:01,810 --> 01:27:04,340 +But this is an Int, right. + +1931 +01:27:04,340 --> 01:27:08,370 +Size is an Int in our Model over here. + +1932 +01:27:08,370 --> 01:27:11,300 +And I don't really want my +View to ever have to deal + +1933 +01:27:11,300 --> 01:27:12,370 +with Ints. + +1934 +01:27:12,370 --> 01:27:14,580 +So I'm gonna put something in my ViewModel + +1935 +01:27:14,580 --> 01:27:16,510 +just like I did all these things, + +1936 +01:27:16,510 --> 01:27:19,540 +doing a little interpretation +here into floats and points. + +1937 +01:27:19,540 --> 01:27:21,100 +I'm gonna do the same thing over here + +1938 +01:27:21,100 --> 01:27:24,220 +for the font size and +for the location as well. + +1939 +01:27:24,220 --> 01:27:25,740 +But I'm gonna do it in an unusual way. + +1940 +01:27:25,740 --> 01:27:29,120 +I'm gonna create an +extension to EmojiArt.Emoji + +1941 +01:27:31,043 --> 01:27:35,040 +and I'm gonna add the var +fontSize which is a CGFloat + +1942 +01:27:36,020 --> 01:27:40,260 +and just takes a CGFloat-ized version + +1943 +01:27:40,260 --> 01:27:43,253 +of self.size. + +1944 +01:27:44,830 --> 01:27:48,380 +Now this might feel like +we're violating MVVM here. + +1945 +01:27:48,380 --> 01:27:53,300 +I just added a CGFloat var to my Model. + +1946 +01:27:53,300 --> 01:27:55,410 +But this is not violating MVVM + +1947 +01:27:55,410 --> 01:27:58,340 +because this code is in +my ViewModel right here. + +1948 +01:27:58,340 --> 01:28:00,930 +It's not in the Model, +I'm adding it to something + +1949 +01:28:00,930 --> 01:28:02,690 +that's in my Model, but this code, + +1950 +01:28:02,690 --> 01:28:06,360 +this line of code right here +is here in my ViewModel. + +1951 +01:28:06,360 --> 01:28:08,140 +And that makes it perfectly legal. + +1952 +01:28:08,140 --> 01:28:11,430 +ViewModel is allowed to +do CGFloat, no problem. + +1953 +01:28:11,430 --> 01:28:16,120 +I can do the same thing here +with location which is CGPoint. + +1954 +01:28:16,120 --> 01:28:19,760 +And I could make that a CGPoint + +1955 +01:28:21,670 --> 01:28:24,567 +where the X is CGFloat sub X + +1956 +01:28:24,567 --> 01:28:27,610 +and the Y is CGFloat sub Y. + +1957 +01:28:27,610 --> 01:28:31,450 +So now I've made it so +that we don't have to deal + +1958 +01:28:31,450 --> 01:28:35,163 +with Ints ever in our View. + +1959 +01:28:36,034 --> 01:28:38,694 +And our ViewModel is just +being a good ViewModel, + +1960 +01:28:38,694 --> 01:28:42,180 +okay by interpreting the Model for us. + +1961 +01:28:42,180 --> 01:28:44,520 +So over here then I can +just say that this size + +1962 +01:28:44,520 --> 01:28:47,240 +equals this Emoji's fontSize. + +1963 +01:28:47,240 --> 01:28:48,857 +And this will be a CGFloat. + +1964 +01:28:50,060 --> 01:28:54,410 +And for the position, similarly +for private func position + +1965 +01:28:54,410 --> 01:28:59,193 +for emoji, EmojiArt.Emoji in size, CGSize. + +1966 +01:29:00,220 --> 01:29:01,500 +That's going to give the CGPoint + +1967 +01:29:01,500 --> 01:29:04,000 +which is where that thing goes. + +1968 +01:29:04,000 --> 01:29:07,270 +That's just gonna make a +CGPoint where we convert again + +1969 +01:29:07,270 --> 01:29:09,000 +to that (0, 0) in the middle + +1970 +01:29:09,000 --> 01:29:10,920 +instead of (0, 0) in the upper left. + +1971 +01:29:10,920 --> 01:29:14,820 +So that's the X being Emoji's location.x + +1972 +01:29:14,820 --> 01:29:18,940 +plus, plus size.width divided by two + +1973 +01:29:18,940 --> 01:29:23,330 +and the Y is the Emoji's location.y. + +1974 +01:29:23,330 --> 01:29:25,880 +Again, this emoji.location, +those are CGPoints + +1975 +01:29:26,767 --> 01:29:28,760 +coming from our ViewModel there. + +1976 +01:29:28,760 --> 01:29:31,253 +Plus size.height divided by two. + +1977 +01:29:32,700 --> 01:29:36,700 +Now you might have some more +conversion going on later + +1978 +01:29:36,700 --> 01:29:38,870 +when you start allowing these things + +1979 +01:29:38,870 --> 01:29:41,590 +to be positioned, moved around. + +1980 +01:29:41,590 --> 01:29:43,632 +And what do we got here, oh yes of course, + +1981 +01:29:43,632 --> 01:29:45,963 +it's not just emoji, it's emoji's text. + +1982 +01:29:47,490 --> 01:29:48,540 +So let's take a look! + +1983 +01:29:50,120 --> 01:29:53,460 +Hopefully that just ForEach'd +all of us text in there. + +1984 +01:29:53,460 --> 01:29:55,940 +Again, let's make a nice background here. + +1985 +01:29:55,940 --> 01:29:59,560 +Let's pick this up, put it +in here, whoo, we got it! + +1986 +01:29:59,560 --> 01:30:02,540 +A little baseball, yay! + +1987 +01:30:02,540 --> 01:30:05,350 +Apple on top of the house, nice! + +1988 +01:30:05,350 --> 01:30:08,300 +Now your homework assignment +next week is going to be, + +1989 +01:30:08,300 --> 01:30:11,110 +it'll make it so you can +click on these to select them + +1990 +01:30:11,110 --> 01:30:14,210 +and then drag them around, okay? + +1991 +01:30:14,210 --> 01:30:17,300 +Or even pinch, which you +can do on your simulator + +1992 +01:30:17,300 --> 01:30:18,970 +by holding down the option key + +1993 +01:30:18,970 --> 01:30:22,130 +and pinch to zoom in and out on them. + +1994 +01:30:22,130 --> 01:30:23,850 +So to get you started on +that and understanding + +1995 +01:30:23,850 --> 01:30:25,330 +how to do that, in the next lecture + +1996 +01:30:25,330 --> 01:30:27,640 +we're gonna make it so +that we can drag around + +1997 +01:30:27,640 --> 01:30:30,690 +and pinch the whole image. + +1998 +01:30:30,690 --> 01:30:32,727 +So I'm gonna let you drag around +and pinch the whole image. + +1999 +01:30:32,727 --> 01:30:34,750 +You're gonna make it +so you can drag around + +2000 +01:30:34,750 --> 01:30:36,743 +and pinch the little emoji there. + +2001 +01:30:39,315 --> 01:30:40,530 +So that's it for this lecture, + +2002 +01:30:40,530 --> 01:30:42,910 +and then we'll start off the next lecture + +2003 +01:30:42,910 --> 01:30:44,670 +with a little bit of slides about how + +2004 +01:30:44,670 --> 01:30:48,467 +to do these gestures, pinches, +and drags and all that stuff + +2005 +01:30:48,467 --> 01:30:50,270 +and then we'll dive +right back into this demo + +2006 +01:30:50,270 --> 01:30:51,913 +and make some more progress. + +2007 +01:30:53,090 --> 01:30:56,323 +- [Presenter] For more, please +visit us at stanford.edu. diff --git a/subtitles/en/Lecture 8. Gestures JSON.srt b/subtitles/en/Lecture 8. Gestures JSON.srt new file mode 100644 index 0000000..dc6a953 --- /dev/null +++ b/subtitles/en/Lecture 8. Gestures JSON.srt @@ -0,0 +1,7439 @@ +1 +00:00:04,940 --> 00:00:06,640 +- Stanford University. + +2 +00:00:08,600 --> 00:00:10,270 +- Okay, welcome to lecture eight, + +3 +00:00:10,270 --> 00:00:14,580 +Stanford CS193p, spring of 2020. + +4 +00:00:14,580 --> 00:00:17,470 +I'm gonna try to keep +the slides short today + +5 +00:00:17,470 --> 00:00:20,430 +so we can jump into another big demo, + +6 +00:00:20,430 --> 00:00:22,910 +but I need to talk about conceptual stuff + +7 +00:00:22,910 --> 00:00:25,470 +behind a couple of things +we're gonna do in the demo, + +8 +00:00:25,470 --> 00:00:28,750 +namely UserDefaults, which +is a very lightweight, + +9 +00:00:28,750 --> 00:00:30,890 +persistent store that we're just gonna use + +10 +00:00:30,890 --> 00:00:32,440 +for demo purposes. + +11 +00:00:32,440 --> 00:00:36,510 +And then, the main meaty topic +of today, which is gestures, + +12 +00:00:36,510 --> 00:00:40,193 +getting input from your user +using their fingers basically. + +13 +00:00:41,040 --> 00:00:43,130 +So, let's talk about +this UserDefaults thing. + +14 +00:00:43,130 --> 00:00:46,600 +Before I do that, I wanna talk +about persistence in general. + +15 +00:00:46,600 --> 00:00:48,670 +By persistence I just mean that + +16 +00:00:48,670 --> 00:00:52,273 +making things stick on your iOS device + +17 +00:00:52,273 --> 00:00:55,340 +even when you quit your +app and restart it. + +18 +00:00:55,340 --> 00:00:58,110 +And there's numerous ways +to make data persist. + +19 +00:00:58,110 --> 00:01:01,107 +You can put it in a file system, iOS. + +20 +00:01:01,107 --> 00:01:04,670 +Basically there's a Unix +machine underneath it all, + +21 +00:01:04,670 --> 00:01:06,400 +and it has a Unix file system, + +22 +00:01:06,400 --> 00:01:08,370 +and you can certainly store +things in the file system. + +23 +00:01:08,370 --> 00:01:11,200 +I hope to cover that later in the quarter. + +24 +00:01:11,200 --> 00:01:13,090 +You could put things in a SQL database + +25 +00:01:13,090 --> 00:01:14,480 +or some other database. + +26 +00:01:14,480 --> 00:01:18,200 +iOS has an awesome +framework called CoreData + +27 +00:01:18,200 --> 00:01:21,650 +that essentially does an object +oriented programming layer + +28 +00:01:21,650 --> 00:01:23,950 +on top of a SQL database. + +29 +00:01:23,950 --> 00:01:25,090 +Really fantastic. + +30 +00:01:25,090 --> 00:01:26,859 +Don't think we're gonna +get to that this quarter, + +31 +00:01:26,859 --> 00:01:30,139 +but I'd like to at least talk +about it later in the quarter. + +32 +00:01:30,139 --> 00:01:32,306 +Of course, we can store things in iCloud. + +33 +00:01:32,306 --> 00:01:33,390 +That's great way, + +34 +00:01:33,390 --> 00:01:36,380 +because it's shared +between all of our devices. + +35 +00:01:36,380 --> 00:01:39,260 +And, in fact, there's an entire +framework called CloudKit, + +36 +00:01:39,260 --> 00:01:42,810 +which let's us do database +operations essentially, + +37 +00:01:42,810 --> 00:01:44,490 +that get stored in the cloud. + +38 +00:01:44,490 --> 00:01:46,540 +So that's a cool way. + +39 +00:01:46,540 --> 00:01:48,772 +And there's many third +party options as well. + +40 +00:01:48,772 --> 00:01:51,200 +Different frameworks +provided by third parties + +41 +00:01:51,200 --> 00:01:53,592 +that do the kind of same +thing, network databases, + +42 +00:01:53,592 --> 00:01:56,468 +places to store things, et cetera. + +43 +00:01:56,468 --> 00:01:59,244 +But one of the simplest +ways to store things + +44 +00:01:59,244 --> 00:02:01,520 +is using something called UserDefaults, + +45 +00:02:01,520 --> 00:02:05,240 +and you can think of it as +a persistent Dictionary. + +46 +00:02:05,240 --> 00:02:08,632 +It feels a lot like a Dictionary +that just sticks on disk, + +47 +00:02:08,632 --> 00:02:11,390 +but it really should only be used, + +48 +00:02:11,390 --> 00:02:13,440 +when you're shipping your app, + +49 +00:02:13,440 --> 00:02:15,420 +you probably only wanna use UserDefaults + +50 +00:02:15,420 --> 00:02:18,832 +for user preferences, small little things. + +51 +00:02:18,832 --> 00:02:21,270 +You don't wanna use it to, for example, + +52 +00:02:21,270 --> 00:02:22,480 +store your documents, + +53 +00:02:22,480 --> 00:02:24,030 +which is what we're gonna do in our demo, + +54 +00:02:24,030 --> 00:02:26,160 +it's why I'm telling +you about UserDefaults, + +55 +00:02:26,160 --> 00:02:29,470 +so we need some lightweight +way to store our documents, + +56 +00:02:29,470 --> 00:02:30,303 +so we're gonna do it. + +57 +00:02:30,303 --> 00:02:32,880 +But I mean, UserDefaults +is valuable though, + +58 +00:02:32,880 --> 00:02:34,720 +for storing these lightweight things, + +59 +00:02:34,720 --> 00:02:37,970 +but you're gonna see there's +some quirkiness to it as well. + +60 +00:02:37,970 --> 00:02:39,922 +Now UserDefaults is quite limited + +61 +00:02:39,922 --> 00:02:42,000 +in the type of data it can store. + +62 +00:02:42,000 --> 00:02:44,740 +This is not just a full +database or a full Dictionary, + +63 +00:02:44,740 --> 00:02:46,790 +you can put any type you want in there. + +64 +00:02:46,790 --> 00:02:50,658 +It's an ancient API I call it, +it's been around a long time, + +65 +00:02:50,658 --> 00:02:54,450 +it far predates SwiftUI or even Swift, + +66 +00:02:54,450 --> 00:02:56,950 +and its API is a little strange + +67 +00:02:56,950 --> 00:02:58,570 +for those of you in this class + +68 +00:02:58,570 --> 00:03:01,610 +who are now really used +to functional programming. + +69 +00:03:01,610 --> 00:03:03,836 +But if we squint at this API, + +70 +00:03:03,836 --> 00:03:08,836 +we can make it look close enough to Swift + +71 +00:03:09,040 --> 00:03:11,579 +and functional programming +for it to fit in. + +72 +00:03:11,579 --> 00:03:15,450 +The data that's stored in UserDefaults + +73 +00:03:15,450 --> 00:03:17,040 +is called a property list. + +74 +00:03:17,040 --> 00:03:21,030 +Now, of property list is +not a protocol or a struct, + +75 +00:03:21,030 --> 00:03:24,630 +or any tangible thing from Swift, + +76 +00:03:24,630 --> 00:03:26,227 +'cause this is all pretty Swift. + +77 +00:03:26,227 --> 00:03:29,140 +But property list is +really just a concept. + +78 +00:03:29,140 --> 00:03:30,390 +It's an idea. + +79 +00:03:30,390 --> 00:03:33,840 +And that idea is that it's +any combination of Strings, + +80 +00:03:33,840 --> 00:03:37,530 +Ints, Bools, floating point +numbers like Float or Double, + +81 +00:03:37,530 --> 00:03:42,530 +Dates, Datas, which are bags +of bits, just arbitrary data, + +82 +00:03:42,540 --> 00:03:43,940 +Arrays and Dictionaries. + +83 +00:03:43,940 --> 00:03:46,171 +So you put any combination +of those together, + +84 +00:03:46,171 --> 00:03:50,891 +like an Array that it has +Dictionaries with Strings + +85 +00:03:50,891 --> 00:03:53,260 +as the keys and Ints as the values, + +86 +00:03:53,260 --> 00:03:54,493 +that would be a property list. + +87 +00:03:54,493 --> 00:03:56,930 +A kinda goofy one, but that +would be a property list + +88 +00:03:56,930 --> 00:04:00,120 +'cause all the things in +there are one of these things. + +89 +00:04:00,120 --> 00:04:01,220 +So that's all we can store there, + +90 +00:04:01,220 --> 00:04:02,470 +we can't store anything else. + +91 +00:04:02,470 --> 00:04:03,800 +If you wanna store anything else, + +92 +00:04:03,800 --> 00:04:07,630 +you have to convert it into +a property list somehow. + +93 +00:04:07,630 --> 00:04:10,200 +Now, a really powerful way in Swift + +94 +00:04:10,200 --> 00:04:14,190 +to convert an arbitrary +struct into a property list + +95 +00:04:14,190 --> 00:04:16,580 +is using this Codable protocol, + +96 +00:04:16,580 --> 00:04:19,410 +and I'm just going to put +that off and show you that + +97 +00:04:19,410 --> 00:04:22,420 +in the demo, rather than having +a bunch of slides about it. + +98 +00:04:22,420 --> 00:04:24,893 +And you'll see, pretty +quickly, how Codable works. + +99 +00:04:24,893 --> 00:04:27,610 +It's a great way to turn +a struct into a Data, + +100 +00:04:27,610 --> 00:04:31,210 +and of course a Data, a bag +of bits, is a property list, + +101 +00:04:31,210 --> 00:04:33,480 +and so we can throw it in UserDefaults. + +102 +00:04:33,480 --> 00:04:35,230 +And we'll see that all in the demo. + +103 +00:04:36,860 --> 00:04:39,880 +Now, why is the API of UserDefaults weird? + +104 +00:04:39,880 --> 00:04:44,010 +Well, because prominently in +that API, is a type in Swift, + +105 +00:04:44,010 --> 00:04:47,780 +which we have not talked about, +intentionally, called Any. + +106 +00:04:47,780 --> 00:04:51,360 +So Any is basically a +type that means untyped. + +107 +00:04:51,360 --> 00:04:52,570 +If something's of type Any, + +108 +00:04:52,570 --> 00:04:54,780 +it's like it doesn't really have a type. + +109 +00:04:54,780 --> 00:04:57,330 +Well Swift is a strongly typed language, + +110 +00:04:57,330 --> 00:04:59,300 +it does not like Any. + +111 +00:04:59,300 --> 00:05:02,003 +Any is antithetical to Swift. + +112 +00:05:02,003 --> 00:05:06,260 +But, it has this type Any just +for backwards compatibility + +113 +00:05:06,260 --> 00:05:08,480 +with things like UserDefaults. + +114 +00:05:08,480 --> 00:05:10,530 +So, we really don't wanna +have anything to do with Any + +115 +00:05:10,530 --> 00:05:13,732 +as SwiftUI and Swift +programmers in general. + +116 +00:05:13,732 --> 00:05:14,840 +But we wanna use UserDefaults, + +117 +00:05:14,840 --> 00:05:19,550 +so we're gonna try to ignore +Any in UserDefaults' API, + +118 +00:05:19,550 --> 00:05:22,400 +which is a challenge, but you can do it. + +119 +00:05:22,400 --> 00:05:24,917 +And yet we still wanna understand +how to use UserDefaults. + +120 +00:05:24,917 --> 00:05:26,453 +So, let's dive in here. + +121 +00:05:27,290 --> 00:05:29,190 +First thing you need +to use UserDefaults is, + +122 +00:05:29,190 --> 00:05:31,380 +you need an instance of UserDefaults, + +123 +00:05:31,380 --> 00:05:33,908 +all the methods functions +that you're gonna use + +124 +00:05:33,908 --> 00:05:36,500 +in UserDefaults are instance methods. + +125 +00:05:36,500 --> 00:05:39,950 +So, we do that usually by this static var + +126 +00:05:39,950 --> 00:05:42,670 +called standard on UserDefaults. + +127 +00:05:42,670 --> 00:05:43,739 +Already kinda weird, right? + +128 +00:05:43,739 --> 00:05:45,880 +So you say UserDefaults dot standard, + +129 +00:05:45,880 --> 00:05:47,730 +and you get this shared +instance you can use + +130 +00:05:47,730 --> 00:05:48,563 +in your entire app. + +131 +00:05:48,563 --> 00:05:52,700 +Now, you can make other instances, +but this is, 99% of time, + +132 +00:05:52,700 --> 00:05:54,509 +how we do it. + +133 +00:05:54,509 --> 00:05:55,933 +And then, if we wanna store data, + +134 +00:05:55,933 --> 00:05:59,572 +we're gonna use this +function called set forKey. + +135 +00:05:59,572 --> 00:06:03,590 +And set takes the first +argument there, which is object, + +136 +00:06:03,590 --> 00:06:05,907 +that object has to be a property list. + +137 +00:06:05,907 --> 00:06:08,800 +So it has to be an Int or Array of Strings + +138 +00:06:08,800 --> 00:06:13,170 +or something that has only +those things we talked about + +139 +00:06:13,170 --> 00:06:14,360 +that could be in a property list. + +140 +00:06:14,360 --> 00:06:15,339 +But it can be anything, + +141 +00:06:15,339 --> 00:06:18,010 +as long as that's all that's in there. + +142 +00:06:18,010 --> 00:06:21,610 +And then forKey is just some +random String, and again, + +143 +00:06:21,610 --> 00:06:22,800 +this is like a Dictionary, + +144 +00:06:22,800 --> 00:06:26,040 +so that's the key to look it up later. + +145 +00:06:26,040 --> 00:06:29,120 +Now, for convenience, there's +also things like setDouble, + +146 +00:06:29,120 --> 00:06:31,550 +which takes a double forKey. + +147 +00:06:31,550 --> 00:06:34,180 +It's syntactic sugar really, + +148 +00:06:34,180 --> 00:06:38,260 +it's no different than +saying set with 37.5, + +149 +00:06:38,260 --> 00:06:39,783 +forKey is the same thing. + +150 +00:06:39,783 --> 00:06:42,230 +But you can see how this looks +like a Dictionary, right? + +151 +00:06:42,230 --> 00:06:45,048 +Setting values for a certain key. + +152 +00:06:45,048 --> 00:06:47,740 +Now how do I get the data back out? + +153 +00:06:47,740 --> 00:06:48,573 +Really easy. + +154 +00:06:48,573 --> 00:06:51,260 +There's a whole bunch of +functions like integer forKey, + +155 +00:06:51,260 --> 00:06:56,200 +data forKey, URL forKey, +even String Array forKey, + +156 +00:06:56,200 --> 00:07:00,130 +where it will go look in +UserDefaults, at that key, + +157 +00:07:00,130 --> 00:07:02,320 +see what anyone has stored there before, + +158 +00:07:02,320 --> 00:07:05,000 +and if it's able to make +it into the type you want, + +159 +00:07:05,000 --> 00:07:08,010 +like a URL or a String +Array, it will return it. + +160 +00:07:08,010 --> 00:07:11,240 +If not, it's going to return nil. + +161 +00:07:11,240 --> 00:07:13,840 +So this is great if it's +one of those basic types, + +162 +00:07:13,840 --> 00:07:17,298 +but what if you have an Array +of something besides Strings? + +163 +00:07:17,298 --> 00:07:18,990 +Well, it starts to get complicated, + +164 +00:07:18,990 --> 00:07:22,440 +and this is where Any starts to come out + +165 +00:07:22,440 --> 00:07:24,920 +in, a monster to get us. + +166 +00:07:24,920 --> 00:07:29,060 +And so, if I try to store +an Array of, let's say, + +167 +00:07:29,060 --> 00:07:33,860 +Dictionaries, that's legal, +but there's no function called + +168 +00:07:33,860 --> 00:07:35,420 +give me the Array of Dictionaries, + +169 +00:07:35,420 --> 00:07:36,253 +there's only Array of String, + +170 +00:07:36,253 --> 00:07:38,370 +that's only Array one there is. + +171 +00:07:38,370 --> 00:07:40,470 +So if you call just Array forKey, + +172 +00:07:40,470 --> 00:07:42,660 +you're gonna get an Array of Any. + +173 +00:07:42,660 --> 00:07:44,682 +And, how do I deal with this Any? + +174 +00:07:44,682 --> 00:07:47,550 +Well, you're gonna have to +use this operator in Swift + +175 +00:07:47,550 --> 00:07:51,329 +called as to typecast +the things in the Array + +176 +00:07:51,329 --> 00:07:54,360 +from Any's to being what +type you hopefully know + +177 +00:07:54,360 --> 00:07:55,750 +what they are. + +178 +00:07:55,750 --> 00:07:57,200 +We're gonna stop right here. + +179 +00:07:57,200 --> 00:07:59,960 +I don't wanna really talk +about typecasting and all that, + +180 +00:07:59,960 --> 00:08:02,860 +you really don't need to +do that very much in Swift. + +181 +00:08:02,860 --> 00:08:04,430 +Now, your reading assignment this week + +182 +00:08:04,430 --> 00:08:05,790 +is going to talk about that, + +183 +00:08:05,790 --> 00:08:07,071 +so if you wanna know about this, + +184 +00:08:07,071 --> 00:08:09,760 +you'll see the section called typecasting, + +185 +00:08:09,760 --> 00:08:11,319 +it'll tell you all about it. + +186 +00:08:11,319 --> 00:08:15,043 +And hopefully though, you can +just avoid this whole thing + +187 +00:08:15,043 --> 00:08:19,800 +by somehow figuring how to +use one of these normal ones + +188 +00:08:19,800 --> 00:08:21,720 +from the top of the screen right here, + +189 +00:08:21,720 --> 00:08:23,490 +and Codable might really help you there, + +190 +00:08:23,490 --> 00:08:25,791 +because then you can use data forKey. + +191 +00:08:25,791 --> 00:08:28,030 +And Codable can help you +turn almost any struct, + +192 +00:08:28,030 --> 00:08:31,823 +even an Array of some +wacky thing, into a Data. + +193 +00:08:33,810 --> 00:08:37,337 +That's all I'm gonna say +about UserDefaults for today. + +194 +00:08:37,337 --> 00:08:39,630 +And we're gonna get onto +our main topic here, + +195 +00:08:39,630 --> 00:08:41,030 +which is gesture. + +196 +00:08:41,030 --> 00:08:44,462 +So gestures is really about +getting input from the user. + +197 +00:08:44,462 --> 00:08:47,720 +We call this multitouch +because, of course, + +198 +00:08:47,720 --> 00:08:50,390 +you can put multiple fingers +down at the same time, + +199 +00:08:50,390 --> 00:08:54,430 +and do gestures and SwiftUI +will recognize them. + +200 +00:08:54,430 --> 00:08:58,230 +Swift pretty much takes care +of recognizing these gestures + +201 +00:08:58,230 --> 00:08:59,840 +when someone puts two fingers down + +202 +00:08:59,840 --> 00:09:01,856 +and start squeezing +their fingers together, + +203 +00:09:01,856 --> 00:09:05,310 +Swift recognizes, whoa, that's +a pinch, they're pinching, + +204 +00:09:05,310 --> 00:09:06,520 +I know that gesture. + +205 +00:09:06,520 --> 00:09:08,840 +So it recognizes them, +all you have to do is say + +206 +00:09:08,840 --> 00:09:11,020 +which Views you want to +recognize which things, + +207 +00:09:11,020 --> 00:09:13,000 +and it'll start recognizing them. + +208 +00:09:13,000 --> 00:09:15,880 +But, it's not just +recognizing them that matters, + +209 +00:09:15,880 --> 00:09:17,935 +once it recognizes that +this pinch is happening, + +210 +00:09:17,935 --> 00:09:21,490 +you and your code have +to handle the gesture. + +211 +00:09:21,490 --> 00:09:23,423 +So there's recognizing +it, Swift does that, + +212 +00:09:23,423 --> 00:09:26,270 +SwiftUI does that, and +then there's handling it, + +213 +00:09:26,270 --> 00:09:27,750 +which is something you have to do. + +214 +00:09:27,750 --> 00:09:29,950 +And handling it just +means deciding what to do + +215 +00:09:29,950 --> 00:09:32,433 +when there's a pinch or a drag or a tap. + +216 +00:09:34,300 --> 00:09:37,940 +So, let's talk first about how +you make your Views recognize + +217 +00:09:37,940 --> 00:09:39,700 +that a certain gesture is happening + +218 +00:09:39,700 --> 00:09:42,890 +using SwiftUI's powerful +gesture recognition. + +219 +00:09:42,890 --> 00:09:46,040 +And it's so simple, there is +just a ViewModifier on View + +220 +00:09:46,040 --> 00:09:49,560 +called .gesture, and +you just pass a Gesture. + +221 +00:09:49,560 --> 00:09:51,950 +This argument that you pass, a Gesture, + +222 +00:09:51,950 --> 00:09:53,430 +just needs to be anything + +223 +00:09:53,430 --> 00:09:55,340 +that implements the Gesture protocol, + +224 +00:09:55,340 --> 00:09:56,590 +and we're gonna talk about + +225 +00:09:56,590 --> 00:09:59,337 +what things implement the +Gesture protocol, and that's it. + +226 +00:09:59,337 --> 00:10:02,230 +And then after that, +your myView right there, + +227 +00:10:02,230 --> 00:10:04,704 +whenever that gesture starts +to happen in your View, + +228 +00:10:04,704 --> 00:10:06,823 +you're going to be asked to handle it. + +229 +00:10:08,350 --> 00:10:09,790 +Now how do we create this Gesture? + +230 +00:10:09,790 --> 00:10:12,260 +How do we specify what +gesture we want here? + +231 +00:10:12,260 --> 00:10:16,110 +We almost always do that with +either a func in our View, + +232 +00:10:16,110 --> 00:10:18,020 +or maybe it's a computed var, + +233 +00:10:18,020 --> 00:10:21,279 +or it even could be a local +var at the top of our body var, + +234 +00:10:21,279 --> 00:10:22,960 +right before we do it. + +235 +00:10:22,960 --> 00:10:25,031 +Anywhere you can store this thing is fine, + +236 +00:10:25,031 --> 00:10:27,900 +and this computer var or func or whatever + +237 +00:10:27,900 --> 00:10:30,680 +just has to return something +that is some Gesture. + +238 +00:10:30,680 --> 00:10:31,860 +So you know what some means, + +239 +00:10:31,860 --> 00:10:34,200 +it means you can return +anything you want in there + +240 +00:10:34,200 --> 00:10:37,420 +as long as it implements that protocol, + +241 +00:10:37,420 --> 00:10:39,950 +and Swift will figure out +that return type for you. + +242 +00:10:39,950 --> 00:10:42,033 +So right here I have var theGesture, + +243 +00:10:42,033 --> 00:10:45,290 +and I'm returning TapGesture count of two. + +244 +00:10:45,290 --> 00:10:48,390 +Swift will know that some +gesture there is TapGesture. + +245 +00:10:48,390 --> 00:10:51,230 +This TapGesture is one of the gestures + +246 +00:10:51,230 --> 00:10:52,110 +that's built into SwiftUI. + +247 +00:10:52,110 --> 00:10:54,470 +You know it well, TapGesture. + +248 +00:10:54,470 --> 00:10:57,380 +This particular one here, +I've made with a count of two. + +249 +00:10:57,380 --> 00:10:58,959 +So this is actually a double tap. + +250 +00:10:58,959 --> 00:11:02,270 +TapGesture has an argument +to its initializer, + +251 +00:11:02,270 --> 00:11:04,640 +which is how many taps, +and my default is one, + +252 +00:11:04,640 --> 00:11:05,913 +but here I've said two. + +253 +00:11:06,840 --> 00:11:09,480 +With a combination of two +things of code you see on here, + +254 +00:11:09,480 --> 00:11:11,140 +the one at the top, and the one at bottom, + +255 +00:11:11,140 --> 00:11:13,315 +Swift will start recognizing a double tap. + +256 +00:11:13,315 --> 00:11:16,530 +But, it won't do anything +when the double tap happens, + +257 +00:11:16,530 --> 00:11:18,530 +'cause we haven't told Swift how to handle + +258 +00:11:18,530 --> 00:11:20,310 +a double tap happening. + +259 +00:11:20,310 --> 00:11:25,060 +So the next step we need +to do is to explain to it + +260 +00:11:25,060 --> 00:11:28,930 +how to handle, and it depends +on the kind of gestures, + +261 +00:11:28,930 --> 00:11:30,170 +how to do this. + +262 +00:11:30,170 --> 00:11:33,250 +So, some gestures are +discrete, like TapGesture, + +263 +00:11:33,250 --> 00:11:36,840 +and LongPressGesture can be discrete, + +264 +00:11:36,840 --> 00:11:40,240 +where it just, the tap happens, +and then go do something. + +265 +00:11:40,240 --> 00:11:42,860 +A LongPressGesture happens, +and then go do something. + +266 +00:11:42,860 --> 00:11:44,760 +That's different than a pinch or a drag, + +267 +00:11:44,760 --> 00:11:47,490 +which, they're happening overtime, + +268 +00:11:47,490 --> 00:11:49,240 +we might wanna get involved in that. + +269 +00:11:49,240 --> 00:11:50,970 +So for discrete gestures, those are easy, + +270 +00:11:50,970 --> 00:11:52,490 +let's get those out of the way. + +271 +00:11:52,490 --> 00:11:55,317 +You do something by calling +the function on your gesture + +272 +00:11:55,317 --> 00:11:58,260 +.onEnded, which takes a closure, + +273 +00:11:58,260 --> 00:12:00,360 +and in that closure you +do whatever you want + +274 +00:12:00,360 --> 00:12:02,370 +when that TapGesture ends. + +275 +00:12:02,370 --> 00:12:04,930 +Which means when the finger +comes back up for a tap, + +276 +00:12:04,930 --> 00:12:06,430 +or, if this is double tap, + +277 +00:12:06,430 --> 00:12:08,747 +the second time the finger comes back up. + +278 +00:12:08,747 --> 00:12:09,930 +And that's it. + +279 +00:12:09,930 --> 00:12:12,470 +Couldn't be easier to +handle a discrete gesture. + +280 +00:12:12,470 --> 00:12:14,340 +And of course, discrete gestures + +281 +00:12:14,340 --> 00:12:15,880 +are so simple and easy to handle, + +282 +00:12:15,880 --> 00:12:18,780 +they have these nice +convenience functions, + +283 +00:12:18,780 --> 00:12:21,240 +you've seen it on TapGesture. + +284 +00:12:21,240 --> 00:12:22,370 +I don't know if you know + +285 +00:12:22,370 --> 00:12:24,820 +that it takes the argument +count too, it does. + +286 +00:12:24,820 --> 00:12:26,030 +And then you just do something. + +287 +00:12:26,030 --> 00:12:28,510 +So that's exactly the same +thing as what we've seen + +288 +00:12:28,510 --> 00:12:29,650 +in the previous two slides. + +289 +00:12:29,650 --> 00:12:32,340 +Here we're just going +to handle a TapGesture. + +290 +00:12:32,340 --> 00:12:33,934 +So, discrete gestures, easy. + +291 +00:12:33,934 --> 00:12:38,503 +Non-discrete gestures, little more work. + +292 +00:12:39,360 --> 00:12:40,650 +In a non-discrete gesture, + +293 +00:12:40,650 --> 00:12:43,560 +you do get to handle when it ends, + +294 +00:12:43,560 --> 00:12:44,720 +which we'll talk about in a second, + +295 +00:12:44,720 --> 00:12:46,320 +just like a discrete gesture. + +296 +00:12:46,320 --> 00:12:49,090 +But you can also handle as it's moving, + +297 +00:12:49,090 --> 00:12:51,600 +as the fingers are pinching together, + +298 +00:12:51,600 --> 00:12:53,360 +or as they're rotating around, + +299 +00:12:53,360 --> 00:12:56,870 +or as the finger is dragging +itself around the screen, + +300 +00:12:56,870 --> 00:12:58,260 +you get to go do something, + +301 +00:12:58,260 --> 00:13:01,120 +redraw your View a whole bunch +of times as it moves around, + +302 +00:13:01,120 --> 00:13:03,470 +whatever you wanna do, you get to do it. + +303 +00:13:03,470 --> 00:13:05,522 +Now, examples of these +non-discrete gestures, + +304 +00:13:05,522 --> 00:13:10,522 +DragGesture, MagnificationGesture, +that's like a pinch, + +305 +00:13:10,750 --> 00:13:13,490 +RotationGesture, that's +like you're turning a dial + +306 +00:13:13,490 --> 00:13:15,350 +with two fingers, put two +fingers on the screen, + +307 +00:13:15,350 --> 00:13:18,440 +it's like turning a dial and +you're specifying some angle, + +308 +00:13:18,440 --> 00:13:20,620 +actually, that changes as you do that. + +309 +00:13:20,620 --> 00:13:23,800 +and even LongPressGesture +can kind of be non-discrete, + +310 +00:13:23,800 --> 00:13:28,512 +where you press and hold, +and so it's going to say + +311 +00:13:28,512 --> 00:13:31,000 +that the finger is holding, +and then when it comes back up + +312 +00:13:31,000 --> 00:13:32,273 +you'll find out it came up. + +313 +00:13:32,273 --> 00:13:33,330 +That's different from a tap. + +314 +00:13:33,330 --> 00:13:35,020 +You don't find out when the tap goes down, + +315 +00:13:35,020 --> 00:13:36,070 +you only find when it goes up, + +316 +00:13:36,070 --> 00:13:37,833 +but a long press, you can find out. + +317 +00:13:38,680 --> 00:13:41,720 +So, let's start by talking +about the end of them. + +318 +00:13:41,720 --> 00:13:43,810 +So, just like discrete, +we can find out the end, + +319 +00:13:43,810 --> 00:13:46,490 +and it's exactly the same .onEnded. + +320 +00:13:46,490 --> 00:13:49,630 +The only difference is, +the function that you pass, + +321 +00:13:49,630 --> 00:13:52,284 +the closure gets an argument. + +322 +00:13:52,284 --> 00:13:55,390 +Because, when a DragGesture ends, + +323 +00:13:55,390 --> 00:13:58,765 +you wanna find out, well, what +happened during that drag? + +324 +00:13:58,765 --> 00:14:01,280 +And so, you're gonna get +a little argument here, + +325 +00:14:01,280 --> 00:14:02,880 +this value argument, + +326 +00:14:02,880 --> 00:14:05,945 +and it's different for +every kind of Gesture, + +327 +00:14:05,945 --> 00:14:08,720 +and that is going to +tell you what happened. + +328 +00:14:08,720 --> 00:14:10,930 +For a DragGesture, the value is a struct + +329 +00:14:10,930 --> 00:14:13,450 +with things like the +starting position of the drag + +330 +00:14:13,450 --> 00:14:15,510 +and the ending position of the finger. + +331 +00:14:15,510 --> 00:14:18,620 +For magnification, it's the +scale of the magnification, + +332 +00:14:18,620 --> 00:14:21,590 +which is how far the fingers are apart + +333 +00:14:21,590 --> 00:14:23,850 +when they lifted up off the screen. + +334 +00:14:23,850 --> 00:14:25,810 +And the RotationGesture, similar, right. + +335 +00:14:25,810 --> 00:14:27,390 +It's like turning a +dial, so it's gonna say + +336 +00:14:27,390 --> 00:14:31,120 +how much angle did it turn +before the fingers lifted up? + +337 +00:14:31,120 --> 00:14:33,510 +Still get to ended, but you +get to find out, of course, + +338 +00:14:33,510 --> 00:14:35,113 +what happens there. + +339 +00:14:36,300 --> 00:14:38,320 +But the more interesting thing is, + +340 +00:14:38,320 --> 00:14:39,725 +during a non-discrete gesture, + +341 +00:14:39,725 --> 00:14:43,096 +you wanna find out as things are changing. + +342 +00:14:43,096 --> 00:14:46,769 +We do this by having some state + +343 +00:14:46,769 --> 00:14:49,570 +that is only going to be in effect + +344 +00:14:49,570 --> 00:14:51,894 +while the Gesture is going on. + +345 +00:14:51,894 --> 00:14:54,990 +This state is stored in any var you want, + +346 +00:14:54,990 --> 00:14:55,960 +you just have to mark it + +347 +00:14:55,960 --> 00:14:58,260 +with this special marker, @GestureState + +348 +00:14:59,470 --> 00:15:02,080 +And you must also give +this var an initial value + +349 +00:15:02,080 --> 00:15:03,450 +of some sort. + +350 +00:15:03,450 --> 00:15:05,210 +This var can be any type you want. + +351 +00:15:05,210 --> 00:15:07,470 +It could be a CGFloat, +it could be a struct + +352 +00:15:07,470 --> 00:15:09,540 +with all kinds of your own stuff in it. + +353 +00:15:09,540 --> 00:15:12,990 +There's no limit on what this var can be. + +354 +00:15:12,990 --> 00:15:15,170 +And what this var is basically going to do + +355 +00:15:15,170 --> 00:15:18,220 +is tell your View, here's all +the things you need to know + +356 +00:15:18,220 --> 00:15:20,450 +to draw yourself in the +middle of this Gesture. + +357 +00:15:20,450 --> 00:15:21,520 +That's what's going on here. + +358 +00:15:21,520 --> 00:15:23,667 +That's what this var is all about. + +359 +00:15:23,667 --> 00:15:26,260 +But it is marked specially, +and we're gonna talk about + +360 +00:15:26,260 --> 00:15:27,460 +what's special about it. + +361 +00:15:28,330 --> 00:15:30,620 +The first thing to understand +that's special about this var + +362 +00:15:30,620 --> 00:15:33,674 +is that it's always gonna +return to that starting value + +363 +00:15:33,674 --> 00:15:34,960 +when the Gesture ends. + +364 +00:15:34,960 --> 00:15:37,100 +That's why you must give +it a starting value. + +365 +00:15:37,100 --> 00:15:38,640 +So while the Gesture is going on, + +366 +00:15:38,640 --> 00:15:42,080 +you're going to be updating +this GestureState of yours + +367 +00:15:42,080 --> 00:15:43,450 +to reflect what's going on in the Gesture + +368 +00:15:43,450 --> 00:15:46,010 +every time the fingers move. + +369 +00:15:46,010 --> 00:15:48,320 +But as soon as the +fingers go up and it ends, + +370 +00:15:48,320 --> 00:15:50,580 +this is gonna get reset +back to starting value. + +371 +00:15:50,580 --> 00:15:52,870 +So you have to understand +that this @GestureState + +372 +00:15:52,870 --> 00:15:55,890 +is only the state while +the Gesture is active. + +373 +00:15:55,890 --> 00:15:57,060 +Very important to understand. + +374 +00:15:57,060 --> 00:15:57,970 +That's why I put this in red, + +375 +00:15:57,970 --> 00:16:01,283 +when the Gesture ends, it goes +back to the starting value. + +376 +00:16:02,510 --> 00:16:04,031 +Now, while the Gesture is happening, + +377 +00:16:04,031 --> 00:16:06,680 +you are given the opportunity, of course, + +378 +00:16:06,680 --> 00:16:08,130 +to change this state. + +379 +00:16:08,130 --> 00:16:09,670 +It's your own state, your own type, + +380 +00:16:09,670 --> 00:16:11,340 +so you're the one who has to change it. + +381 +00:16:11,340 --> 00:16:13,120 +And here's how you do that. + +382 +00:16:13,120 --> 00:16:16,270 +Just like you had .onEnded, +you have another function + +383 +00:16:16,270 --> 00:16:18,140 +on your DragGesture called .updating. + +384 +00:16:18,140 --> 00:16:20,200 +Now there's a lot of +colors on the screen here, + +385 +00:16:20,200 --> 00:16:23,920 +so let's go through all these +different colors we have. + +386 +00:16:23,920 --> 00:16:27,110 +The updating function takes two arguments, + +387 +00:16:27,110 --> 00:16:30,300 +and the first one in parentheses there is + +388 +00:16:30,300 --> 00:16:32,050 +your GestureState var. + +389 +00:16:32,050 --> 00:16:35,550 +So you're gonna pass your +GestureState var to .updating. + +390 +00:16:35,550 --> 00:16:37,590 +Notice that you have to put +a dollar in the front of it, + +391 +00:16:37,590 --> 00:16:40,350 +I'll talk a little bit about +that in the demo, why that is, + +392 +00:16:40,350 --> 00:16:43,200 +but really, we're not gonna +talk about this until next week. + +393 +00:16:43,200 --> 00:16:44,657 +But just always put a dollar + +394 +00:16:44,657 --> 00:16:46,883 +in front of your @GestureState var. + +395 +00:16:47,870 --> 00:16:50,860 +Just like .onEnded, +.updating takes a closure + +396 +00:16:50,860 --> 00:16:51,693 +that it's gonna call. + +397 +00:16:51,693 --> 00:16:53,420 +Now, it's gonna call that thing repeatedly + +398 +00:16:53,420 --> 00:16:55,420 +as the fingers are moving closer together, + +399 +00:16:55,420 --> 00:16:58,030 +or the fingers dragging across +the screen, or whatever, + +400 +00:16:58,030 --> 00:17:00,550 +it's gonna be calling this +closure over and over and over. + +401 +00:17:00,550 --> 00:17:02,800 +So what are the three +arguments we have there + +402 +00:17:02,800 --> 00:17:03,871 +to the closure? + +403 +00:17:03,871 --> 00:17:07,120 +The first one, that blue value argument, + +404 +00:17:07,120 --> 00:17:08,930 +that's the same thing is .onEnded. + +405 +00:17:08,930 --> 00:17:10,960 +That is, the state of this Gesture. + +406 +00:17:10,960 --> 00:17:13,294 +How close the fingers are +together for pinching, + +407 +00:17:13,294 --> 00:17:16,800 +how far they finger has moved +if we're dragging, whatever. + +408 +00:17:16,800 --> 00:17:17,633 +It's a struct. + +409 +00:17:17,633 --> 00:17:21,050 +It depends on which Gesture +we're talking about here + +410 +00:17:21,050 --> 00:17:22,350 +as to what's in there. + +411 +00:17:22,350 --> 00:17:24,050 +Might not be a struct, like magnification + +412 +00:17:24,050 --> 00:17:26,240 +I think it's just a CGFloat with a scale. + +413 +00:17:26,240 --> 00:17:27,640 +But for DragGestures, it's a struct, + +414 +00:17:27,640 --> 00:17:29,990 +with start location, end +location, timestamps, + +415 +00:17:29,990 --> 00:17:31,620 +other things in there. + +416 +00:17:31,620 --> 00:17:32,760 +So that's what that value is. + +417 +00:17:32,760 --> 00:17:35,540 +You're used to that, same as .onEnded. + +418 +00:17:35,540 --> 00:17:38,440 +The myGestureState purple argument there, + +419 +00:17:38,440 --> 00:17:42,010 +is essentially your @GestureState again. + +420 +00:17:42,010 --> 00:17:43,090 +And not only is it there, + +421 +00:17:43,090 --> 00:17:46,390 +it's also inside this little closure. + +422 +00:17:46,390 --> 00:17:48,270 +And you can assign it a value in there. + +423 +00:17:48,270 --> 00:17:52,130 +So, I'm gonna talk in +the demo briefly about + +424 +00:17:52,130 --> 00:17:55,480 +what's going on here, that's +essentially an inout parameter, + +425 +00:17:55,480 --> 00:17:57,180 +but all you really need to know + +426 +00:17:57,180 --> 00:17:59,040 +for the purposes of making this work, + +427 +00:17:59,040 --> 00:18:02,830 +is that your @GestureState variable + +428 +00:18:02,830 --> 00:18:06,213 +appears in these three places +as the argument to .updating, + +429 +00:18:06,213 --> 00:18:08,550 +as the second argument to the closure, + +430 +00:18:08,550 --> 00:18:12,250 +and then inside as a +changeable writable var + +431 +00:18:12,250 --> 00:18:13,640 +that you can change. + +432 +00:18:13,640 --> 00:18:16,011 +Now, if you wanna just put +your hands over your eyes + +433 +00:18:16,011 --> 00:18:18,040 +and not think about it, + +434 +00:18:18,040 --> 00:18:20,090 +you can just think that +inside this closure + +435 +00:18:20,090 --> 00:18:22,797 +you can change your @GestureState var. + +436 +00:18:22,797 --> 00:18:26,489 +That's not actually what's +happening, but it feels like it. + +437 +00:18:26,489 --> 00:18:29,470 +But the conceptual semantic +thing that's going on here, + +438 +00:18:29,470 --> 00:18:31,800 +in fact, is that this is the only way + +439 +00:18:31,800 --> 00:18:34,324 +you're supposed to change +your @GestureState. + +440 +00:18:34,324 --> 00:18:38,270 +You cannot change your +myGestureState any other place + +441 +00:18:38,270 --> 00:18:40,307 +except for right inside this closure. + +442 +00:18:40,307 --> 00:18:43,530 +And that makes sense, +because this @GestureState + +443 +00:18:43,530 --> 00:18:47,420 +is only supposed to be active +when the Gesture is going on. + +444 +00:18:47,420 --> 00:18:49,700 +So you would never wanna +set it at any other time. + +445 +00:18:49,700 --> 00:18:51,690 +There's actually no reason +to set it any other time + +446 +00:18:51,690 --> 00:18:53,140 +then while this thing's going on, + +447 +00:18:53,140 --> 00:18:55,303 +'cause that's all the @GestureState is. + +448 +00:18:56,600 --> 00:18:57,610 +Very important to understand, + +449 +00:18:57,610 --> 00:19:00,187 +this is the only place you +change your @GestureState var. + +450 +00:19:00,187 --> 00:19:01,760 +And you can change it +to anything you want, + +451 +00:19:01,760 --> 00:19:03,980 +and you're almost always going +to change it to something + +452 +00:19:03,980 --> 00:19:06,010 +based on what that blue value is, right. + +453 +00:19:06,010 --> 00:19:08,160 +Depending on how close +the fingers are together, + +454 +00:19:08,160 --> 00:19:09,370 +how much they've moved. + +455 +00:19:09,370 --> 00:19:12,232 +You're gonna update your +little @GestureState struct + +456 +00:19:12,232 --> 00:19:14,830 +so that your View draws itself properly + +457 +00:19:14,830 --> 00:19:17,273 +in the middle of a drag or a pinch. + +458 +00:19:18,420 --> 00:19:20,420 +Now, the third argument +there, transaction, + +459 +00:19:20,420 --> 00:19:21,726 +has to do with animation. + +460 +00:19:21,726 --> 00:19:23,640 +We're not gonna talk +about that in this course. + +461 +00:19:23,640 --> 00:19:24,830 +There are some limits, + +462 +00:19:24,830 --> 00:19:26,570 +we just don't have time +to talk about everything. + +463 +00:19:26,570 --> 00:19:27,920 +You can look at the documentation + +464 +00:19:27,920 --> 00:19:29,850 +if you wanna try and +figure out transaction. + +465 +00:19:29,850 --> 00:19:33,040 +It's for advanced animation +interactions between Views, + +466 +00:19:33,040 --> 00:19:36,083 +we just have to draw the line somewhere. + +467 +00:19:37,180 --> 00:19:40,840 +Now, there is actually +simpler version of .updating, + +468 +00:19:40,840 --> 00:19:41,990 +it's called .onChanged. + +469 +00:19:43,090 --> 00:19:45,760 +And, when you first see +this you might be like, + +470 +00:19:45,760 --> 00:19:47,630 +oh this is simpler, I'm gonna use this, + +471 +00:19:47,630 --> 00:19:50,250 +but it's only for +certain kinds of changes. + +472 +00:19:50,250 --> 00:19:51,937 +And I'll explain that in a second. + +473 +00:19:51,937 --> 00:19:55,000 +So, .onChanged looks just like .updating, + +474 +00:19:55,000 --> 00:19:57,440 +except for, there's +not that @GestureState. + +475 +00:19:57,440 --> 00:19:58,788 +Because in the .onChanged, + +476 +00:19:58,788 --> 00:20:01,710 +you don't get to update any @GestureState. + +477 +00:20:01,710 --> 00:20:03,342 +This value is passed to you, + +478 +00:20:03,342 --> 00:20:05,610 +and you just have to do +something based on it. + +479 +00:20:05,610 --> 00:20:07,883 +And that's why it's +quite limited to do this. + +480 +00:20:07,883 --> 00:20:10,703 +But, there are some kinds +of things that you can do, + +481 +00:20:10,703 --> 00:20:12,560 +and what are those things? + +482 +00:20:12,560 --> 00:20:14,660 +Well, if you were doing something where + +483 +00:20:14,660 --> 00:20:18,280 +you're actually interested in +the actual finger positions, + +484 +00:20:18,280 --> 00:20:20,440 +like you're doing, drag to select, right, + +485 +00:20:20,440 --> 00:20:22,120 +you're dragging your +finger across the screen + +486 +00:20:22,120 --> 00:20:24,400 +to select objects or something like that, + +487 +00:20:24,400 --> 00:20:29,003 +then you just wanna know where +that drag out is right now. + +488 +00:20:29,900 --> 00:20:32,200 +That's different then if you're pinching + +489 +00:20:32,200 --> 00:20:35,530 +to scale something up or down, +or moving something around, + +490 +00:20:35,530 --> 00:20:38,530 +or whatever, relative +to where it was before. + +491 +00:20:38,530 --> 00:20:40,340 +It's like absolute finger position, or, + +492 +00:20:40,340 --> 00:20:43,263 +you're gonna follow the finger +around and draw like a pen + +493 +00:20:43,263 --> 00:20:45,170 +in your app or something. + +494 +00:20:45,170 --> 00:20:46,820 +Then you might want this. + +495 +00:20:46,820 --> 00:20:48,150 +But, most of the time you're interested + +496 +00:20:48,150 --> 00:20:49,450 +in the relative change. + +497 +00:20:49,450 --> 00:20:51,390 +How much you've pinched down? + +498 +00:20:51,390 --> 00:20:53,630 +How far you've dragged across screen? + +499 +00:20:53,630 --> 00:20:55,283 +And when you're interested +in relative changes, + +500 +00:20:55,283 --> 00:20:57,693 +that's when you need .updating. + +501 +00:20:59,410 --> 00:21:02,210 +All right, so I'm gonna summarize + +502 +00:21:02,210 --> 00:21:04,600 +all the things I just +said here in one slide. + +503 +00:21:04,600 --> 00:21:06,580 +So this is a chance for you to review + +504 +00:21:06,580 --> 00:21:07,630 +and get it all at once. + +505 +00:21:07,630 --> 00:21:10,900 +So here's how we handle +non-discrete gestures + +506 +00:21:10,900 --> 00:21:12,510 +when the fingers are moving. + +507 +00:21:12,510 --> 00:21:14,950 +First, we're gonna collect +any information that we need + +508 +00:21:14,950 --> 00:21:17,223 +to draw our View while +the gesture's happening + +509 +00:21:17,223 --> 00:21:19,130 +into a @GestureState var. + +510 +00:21:19,130 --> 00:21:22,397 +Might only just be a CGFloat, +might be a whole struct. + +511 +00:21:22,397 --> 00:21:25,208 +Then, we're gonna add +.updating to our Gesture. + +512 +00:21:25,208 --> 00:21:28,160 +Whatever our pinch or drag is. + +513 +00:21:28,160 --> 00:21:31,420 +And inside the .updating +closure that we passed, + +514 +00:21:31,420 --> 00:21:32,660 +we're gonna get the value + +515 +00:21:32,660 --> 00:21:35,350 +of what's going on with +the Gesture, repeatedly. + +516 +00:21:35,350 --> 00:21:37,450 +It's gonna constantly call +us with the latest value + +517 +00:21:37,450 --> 00:21:39,080 +of what's going on. + +518 +00:21:39,080 --> 00:21:42,030 +We are going to update our @GestureState, + +519 +00:21:42,030 --> 00:21:44,100 +but we're gonna understand +that that @GestureState, + +520 +00:21:44,100 --> 00:21:46,800 +when the thing ends, is gonna go away. + +521 +00:21:46,800 --> 00:21:48,540 +And go back to its starting value. + +522 +00:21:48,540 --> 00:21:51,770 +So, in .onEnded of a non-discrete Gesture, + +523 +00:21:51,770 --> 00:21:54,210 +we're gonna be sure to update +whatever we need to do, + +524 +00:21:54,210 --> 00:21:56,520 +so that when that thing goes +back to its starting value, + +525 +00:21:56,520 --> 00:21:58,253 +our View still draws properly. + +526 +00:22:00,080 --> 00:22:02,980 +All right, so let's hop into the demo. + +527 +00:22:02,980 --> 00:22:04,870 +I'm gonna show you that +Codable thing I talked about. + +528 +00:22:04,870 --> 00:22:07,070 +We're gonna use UserDefaults +to store our document, + +529 +00:22:07,070 --> 00:22:09,470 +because I didn't have time so far + +530 +00:22:09,470 --> 00:22:11,350 +to teach you about the +file system and all that. + +531 +00:22:11,350 --> 00:22:12,920 +There's quite a bit involved there, + +532 +00:22:12,920 --> 00:22:14,090 +so we'll do that later. + +533 +00:22:14,090 --> 00:22:16,855 +I'm gonna do some other +cool stuff, animating fonts, + +534 +00:22:16,855 --> 00:22:20,025 +but mostly what we're gonna +do today is do some gestures + +535 +00:22:20,025 --> 00:22:21,290 +in our EmojiArt, + +536 +00:22:21,290 --> 00:22:23,650 +make it so we can make our +document bigger and smaller, + +537 +00:22:23,650 --> 00:22:25,693 +and pan around in it, that kinda stuff. + +538 +00:22:27,560 --> 00:22:30,860 +All right, let's continue +to improve our EmojiArt. + +539 +00:22:30,860 --> 00:22:34,300 +And it has a big problem, currently. + +540 +00:22:34,300 --> 00:22:39,300 +For example, if start building +a really beautiful EmojiArt, + +541 +00:22:39,444 --> 00:22:43,243 +some apples at the base of our tree, + +542 +00:22:43,243 --> 00:22:47,227 +and then, I quit my app, when I come back, + +543 +00:22:47,227 --> 00:22:49,800 +I've lost all the work that I've done. + +544 +00:22:49,800 --> 00:22:52,000 +So, that's not good. + +545 +00:22:52,000 --> 00:22:53,380 +Next week or the week after, + +546 +00:22:53,380 --> 00:22:55,720 +we'll actually work on +having multiple documents, + +547 +00:22:55,720 --> 00:22:58,850 +and a document chooser, and all that. + +548 +00:22:58,850 --> 00:23:00,685 +But today, let's just try and work on + +549 +00:23:00,685 --> 00:23:03,560 +making our document persist. + +550 +00:23:03,560 --> 00:23:07,080 +When we make something +persist, what do we need? + +551 +00:23:07,080 --> 00:23:08,330 +Kinda need two things. + +552 +00:23:08,330 --> 00:23:12,210 +One, need some sort of +file format to store it in. + +553 +00:23:12,210 --> 00:23:13,951 +And then we need a place to put it. + +554 +00:23:13,951 --> 00:23:16,380 +Probably the place +we're gonna wanna put it + +555 +00:23:16,380 --> 00:23:17,800 +is in the file system, + +556 +00:23:17,800 --> 00:23:20,370 +and I'm hoping to get +around to showing you that + +557 +00:23:20,370 --> 00:23:21,870 +in a couple of weeks. + +558 +00:23:21,870 --> 00:23:23,000 +But, in the meantime, + +559 +00:23:23,000 --> 00:23:25,270 +we're just gonna put it in UserDefaults, + +560 +00:23:25,270 --> 00:23:27,440 +which we talked about in the slides today. + +561 +00:23:27,440 --> 00:23:29,430 +Now, UserDefaults is +totally the wrong place + +562 +00:23:29,430 --> 00:23:32,130 +to put a document, but it's a really easy, + +563 +00:23:32,130 --> 00:23:35,060 +one line of code, bam, +it's in the UserDefaults. + +564 +00:23:35,060 --> 00:23:36,960 +And really, what we're focused on here, + +565 +00:23:36,960 --> 00:23:39,570 +is not where we're storing it, but more, + +566 +00:23:39,570 --> 00:23:41,510 +what file format are we gonna use, + +567 +00:23:41,510 --> 00:23:44,270 +and how do we generate that file format. + +568 +00:23:44,270 --> 00:23:47,100 +And the file format +we're gonna use is JSON. + +569 +00:23:47,100 --> 00:23:50,649 +So, most of you probably +have heard of JSON before. + +570 +00:23:50,649 --> 00:23:52,622 +It's a file format that's used, + +571 +00:23:52,622 --> 00:23:55,910 +mostly to pass things +around on the Internet. + +572 +00:23:55,910 --> 00:23:57,965 +It's a public file format. + +573 +00:23:57,965 --> 00:24:01,460 +And iOS has awesome feature built in + +574 +00:24:01,460 --> 00:24:03,715 +where it will generate JSON + +575 +00:24:03,715 --> 00:24:08,715 +from almost any struct +that you can imagine. + +576 +00:24:08,740 --> 00:24:12,800 +So, we have our EmojiArtDocument +as a struct in our Model, + +577 +00:24:12,800 --> 00:24:15,288 +and we can use this cool iOS feature + +578 +00:24:15,288 --> 00:24:18,750 +to generate a JSON version of it. + +579 +00:24:18,750 --> 00:24:19,640 +So let's do that. + +580 +00:24:19,640 --> 00:24:23,340 +Let's hop back in here, go to +our Model, here's our Model. + +581 +00:24:23,340 --> 00:24:26,333 +And we just wanna turn +this whole thing here + +582 +00:24:26,333 --> 00:24:28,580 +into a blob of JSON. + +583 +00:24:28,580 --> 00:24:29,730 +So how do we do that? + +584 +00:24:29,730 --> 00:24:32,870 +I'm going to have a var called json. + +585 +00:24:32,870 --> 00:24:34,448 +It's gonna return a Data. + +586 +00:24:34,448 --> 00:24:38,848 +Now, this Data is just a bag of bits. + +587 +00:24:38,848 --> 00:24:42,599 +In our case, it's going +to have JSON in there. + +588 +00:24:42,599 --> 00:24:47,130 +So I'm just gonna return +trying to use a JSONEncoder + +589 +00:24:48,879 --> 00:24:53,280 +to encode myself. + +590 +00:24:53,280 --> 00:24:55,930 +This is the only line +of code we really need + +591 +00:24:55,930 --> 00:24:59,320 +to generate a JSON version of ourself. + +592 +00:24:59,320 --> 00:25:01,230 +But you can see we have an error here. + +593 +00:25:01,230 --> 00:25:03,910 +It says instance method encode + +594 +00:25:03,910 --> 00:25:08,020 +requires that EmojiArt +conform to Encodable. + +595 +00:25:08,020 --> 00:25:10,830 +All right, so, this is +functional programming, + +596 +00:25:10,830 --> 00:25:14,260 +of course there's a protocol +involved, Encodable. + +597 +00:25:14,260 --> 00:25:16,210 +So, our EmojiArt, essentially, + +598 +00:25:16,210 --> 00:25:19,862 +Encodable has to be +something it conforms to. + +599 +00:25:19,862 --> 00:25:23,370 +And, amazingly, because +of extensions, again, + +600 +00:25:23,370 --> 00:25:26,830 +that are in Swift, usually +you could just put Encodable + +601 +00:25:26,830 --> 00:25:29,370 +on a struct and it'll just work. + +602 +00:25:29,370 --> 00:25:31,690 +But, this one doesn't quite work. + +603 +00:25:31,690 --> 00:25:35,640 +And, it's gonna work or not, +depending on whether each var + +604 +00:25:35,640 --> 00:25:39,640 +that's in your struct is itself Encodable. + +605 +00:25:39,640 --> 00:25:40,710 +So let's look at our vars. + +606 +00:25:40,710 --> 00:25:42,327 +We got the background URL. + +607 +00:25:42,327 --> 00:25:46,348 +URL, definitely that's Encodable, +I can guarantee you that. + +608 +00:25:46,348 --> 00:25:48,470 +Emojis, what type is it? + +609 +00:25:48,470 --> 00:25:49,670 +It's an Array. + +610 +00:25:49,670 --> 00:25:51,890 +Arrays, definitely Encodable. + +611 +00:25:51,890 --> 00:25:53,033 +But what's in the Array? + +612 +00:25:53,033 --> 00:25:54,470 +Emoji. + +613 +00:25:54,470 --> 00:25:55,809 +Oh, that's this struct. + +614 +00:25:55,809 --> 00:25:59,170 +Ah, okay, this struct is not Encodable. + +615 +00:25:59,170 --> 00:26:03,640 +No problem, we'll just +say Encodable, and again, + +616 +00:26:03,640 --> 00:26:05,290 +using the same mechanism, + +617 +00:26:05,290 --> 00:26:08,010 +Swift has automatically made it Encodable, + +618 +00:26:08,010 --> 00:26:10,770 +and now everything in my +EmojiArt is Encodable. + +619 +00:26:10,770 --> 00:26:14,490 +So, it's Encodable, and +everything in this Emoji struct + +620 +00:26:14,490 --> 00:26:15,760 +is also Encodable. + +621 +00:26:15,760 --> 00:26:17,689 +Strings, Ints, those are Encodable. + +622 +00:26:17,689 --> 00:26:20,172 +So, this is Encodable. + +623 +00:26:20,172 --> 00:26:24,270 +Now, we almost never +make a struct Encodable + +624 +00:26:24,270 --> 00:26:26,717 +without also being Decodable. + +625 +00:26:27,622 --> 00:26:30,020 +It's no use turning something into a JSON + +626 +00:26:30,020 --> 00:26:33,740 +if you can't turn it back +into one of these things. + +627 +00:26:33,740 --> 00:26:36,693 +And we'll make both of +these Decodable, of course. + +628 +00:26:37,530 --> 00:26:39,220 +It's so common, in fact, + +629 +00:26:39,220 --> 00:26:41,650 +to have both Encodable and Decodable. + +630 +00:26:41,650 --> 00:26:44,760 +Now there's another protocol +that inherits both of them + +631 +00:26:44,760 --> 00:26:46,820 +which is Codable. + +632 +00:26:46,820 --> 00:26:49,715 +So this is the protocol +we're gonna specify + +633 +00:26:49,715 --> 00:26:54,715 +when we wanna make something +be turnable into JSON. + +634 +00:26:56,510 --> 00:26:59,687 +So nothing more is required +in making this Codable. + +635 +00:26:59,687 --> 00:27:01,264 +If you have a struct + +636 +00:27:01,264 --> 00:27:05,460 +that doesn't have standard types like this + +637 +00:27:05,460 --> 00:27:07,912 +or sub structs that can be marked Codable, + +638 +00:27:07,912 --> 00:27:09,980 +Codable is a protocol, + +639 +00:27:09,980 --> 00:27:12,320 +it's got functions in +there that you can use + +640 +00:27:12,320 --> 00:27:16,180 +to turn anything into an encoded thing + +641 +00:27:16,180 --> 00:27:18,220 +that can be JSON-ized. + +642 +00:27:18,220 --> 00:27:21,970 +But, most of the time, we +try to use simple types + +643 +00:27:21,970 --> 00:27:23,330 +that we can do it on. + +644 +00:27:23,330 --> 00:27:26,860 +So, it's not really within the realm, + +645 +00:27:26,860 --> 00:27:28,810 +we're only in week four of this class, + +646 +00:27:28,810 --> 00:27:31,640 +and not really in our knowledge base yet + +647 +00:27:31,640 --> 00:27:33,790 +to go off and make something Codable + +648 +00:27:33,790 --> 00:27:35,070 +that doesn't use standard types, + +649 +00:27:35,070 --> 00:27:36,300 +but you know where to start. + +650 +00:27:36,300 --> 00:27:37,640 +You can go look at this protocol, + +651 +00:27:37,640 --> 00:27:40,070 +see what the description of it is, + +652 +00:27:40,070 --> 00:27:41,893 +and, if you ever needed to, + +653 +00:27:41,893 --> 00:27:45,150 +you could make your own structs Codable, + +654 +00:27:45,150 --> 00:27:47,633 +even if they weren't using +these standard types. + +655 +00:27:48,622 --> 00:27:51,970 +So now we have the JSON, +I wanna look at this, + +656 +00:27:51,970 --> 00:27:53,390 +I wanna see this JSON. + +657 +00:27:53,390 --> 00:27:56,270 +So what I'm gonna do, actually, +is go back to my document, + +658 +00:27:56,270 --> 00:27:58,520 +and every time I change my EmojiArt, + +659 +00:27:58,520 --> 00:28:00,527 +I'm gonna print out on the console + +660 +00:28:00,527 --> 00:28:03,490 +a JSON representation of it. + +661 +00:28:03,490 --> 00:28:05,410 +When I say every time this changes, + +662 +00:28:05,410 --> 00:28:09,344 +some of you are thinking oh +yeah, we know how to do that, + +663 +00:28:09,344 --> 00:28:13,690 +didSet right, this is a property observer. + +664 +00:28:13,690 --> 00:28:18,240 +This is gonna get called every +time EmojiArt gets changed. + +665 +00:28:18,240 --> 00:28:21,650 +Unfortunately, there's a +bug in Swift right now, + +666 +00:28:21,650 --> 00:28:23,740 +and if you're watching this + +667 +00:28:23,740 --> 00:28:25,470 +after the Stanford quarter is over, + +668 +00:28:25,470 --> 00:28:28,830 +it's quite possible that this +bug has been fixed in Swift. + +669 +00:28:28,830 --> 00:28:31,506 +But during the Stanford +quarter, it's not yet fixed. + +670 +00:28:31,506 --> 00:28:34,223 +And the problem is that property wrappers, + +671 +00:28:34,223 --> 00:28:37,417 +which is what this @Published is, + +672 +00:28:37,417 --> 00:28:41,010 +and @State is also a +property wrapper, et cetera. + +673 +00:28:41,010 --> 00:28:45,820 +These don't play well currently +with property observers. + +674 +00:28:45,820 --> 00:28:49,440 +That's a known problem +that's gonna get fixed soon, + +675 +00:28:49,440 --> 00:28:50,730 +at least I hope. + +676 +00:28:50,730 --> 00:28:53,330 +But it keeps us from +doing this nice thing, + +677 +00:28:53,330 --> 00:28:56,000 +where in here we could just say print + +678 +00:28:56,000 --> 00:29:00,000 +the JSON version of my EmojiArt equals, + +679 +00:29:00,000 --> 00:29:03,930 +and here I'll just say emojiArt.json. + +680 +00:29:03,930 --> 00:29:07,930 +And this JSON is a data, of +course, an Optional data, + +681 +00:29:07,930 --> 00:29:10,630 +and I wanna turn it into a UTF-8 String. + +682 +00:29:10,630 --> 00:29:15,630 +So UTF-8 is a String in +coding that JSON always uses. + +683 +00:29:16,370 --> 00:29:18,840 +And since this might be nil, if it's nil, + +684 +00:29:18,840 --> 00:29:21,430 +then return the String nil. + +685 +00:29:21,430 --> 00:29:24,840 +This utf8 var is something +that I added to data + +686 +00:29:24,840 --> 00:29:28,410 +in the EmojiArt extension, +so you can check that out. + +687 +00:29:28,410 --> 00:29:31,810 +So, it would be nice if we +could just have this print out + +688 +00:29:31,810 --> 00:29:33,350 +every time this changes. + +689 +00:29:33,350 --> 00:29:35,950 +Since these two aren't +compatible, what we're gonna do + +690 +00:29:35,950 --> 00:29:39,470 +is stop having this be @Published, + +691 +00:29:39,470 --> 00:29:41,203 +we're gonna take that out of there. + +692 +00:29:41,203 --> 00:29:43,030 +And we're even gonna +mark here that this is + +693 +00:29:43,030 --> 00:29:48,030 +a workaround for property observer problem + +694 +00:29:49,820 --> 00:29:53,160 +with property wrappers. + +695 +00:29:53,160 --> 00:29:56,830 +And instead, we still need this EmojiArt + +696 +00:29:56,830 --> 00:30:00,030 +when it's going to change to +do the ObservableObject thing. + +697 +00:30:00,030 --> 00:30:02,890 +And this is a good +reminder what that's doing, + +698 +00:30:02,890 --> 00:30:04,838 +and I'm gonna do it in my willSet, + +699 +00:30:04,838 --> 00:30:07,853 +objectWillChange.send. + +700 +00:30:09,300 --> 00:30:12,730 +That's what this +ObservableObject thing is doing + +701 +00:30:12,730 --> 00:30:15,130 +when we're Published, its publishing this + +702 +00:30:15,130 --> 00:30:17,730 +something changed message. + +703 +00:30:17,730 --> 00:30:19,560 +So we mentioned that way back when + +704 +00:30:19,560 --> 00:30:22,150 +we first talked about ObervableObject, + +705 +00:30:22,150 --> 00:30:23,690 +but just as reminder. + +706 +00:30:23,690 --> 00:30:24,840 +So I'm doing that myself, + +707 +00:30:24,840 --> 00:30:26,777 +now this is not quite as good + +708 +00:30:26,777 --> 00:30:29,520 +as having this being published. + +709 +00:30:29,520 --> 00:30:32,540 +We really haven't learned +enough about @Publish + +710 +00:30:32,540 --> 00:30:34,580 +and what it's doing to understand + +711 +00:30:34,580 --> 00:30:36,390 +why this is not quite as good. + +712 +00:30:36,390 --> 00:30:38,970 +It's gonna work for +our purposes just fine, + +713 +00:30:38,970 --> 00:30:41,450 +but @Publish, actually +is providing something + +714 +00:30:41,450 --> 00:30:44,220 +called a publisher for +this thing changing, + +715 +00:30:44,220 --> 00:30:45,180 +and we can use that. + +716 +00:30:45,180 --> 00:30:47,147 +In fact, if we knew more about published + +717 +00:30:47,147 --> 00:30:48,660 +at this point in the quarter, + +718 +00:30:48,660 --> 00:30:51,450 +we could use it to do this +workaround in a different way + +719 +00:30:51,450 --> 00:30:53,620 +that would probably be a little better. + +720 +00:30:53,620 --> 00:30:56,130 +But this is fine, this +makes it work for us. + +721 +00:30:56,130 --> 00:30:57,080 +We're still going to have + +722 +00:30:57,080 --> 00:30:59,580 +our ObservableObject notice changes, + +723 +00:30:59,580 --> 00:31:01,790 +and we're gonna print +out JSON on every time + +724 +00:31:01,790 --> 00:31:04,340 +our EmojiArt changes. + +725 +00:31:04,340 --> 00:31:06,393 +Let's take a look, see if that worked. + +726 +00:31:10,800 --> 00:31:14,380 +And I'm gonna drag something, +now, as soon as I drop this, + +727 +00:31:14,380 --> 00:31:17,590 +I believe my EmojiArt should +change and I should see JSON. + +728 +00:31:17,590 --> 00:31:18,530 +Ready? + +729 +00:31:18,530 --> 00:31:20,370 +Boom, woo hoo, we did. + +730 +00:31:20,370 --> 00:31:21,410 +In fact, let's make this smaller, + +731 +00:31:21,410 --> 00:31:23,070 +we can see it going at the same time. + +732 +00:31:23,070 --> 00:31:25,864 +There's our JSON down here, +it's got the background image. + +733 +00:31:25,864 --> 00:31:27,300 +Let's see the emojis. + +734 +00:31:27,300 --> 00:31:29,471 +No emojis 'cause I +haven't put any emojis in. + +735 +00:31:29,471 --> 00:31:31,189 +Let's go and put an emoji in. + +736 +00:31:31,189 --> 00:31:33,590 +Maybe an apple below the tree again. + +737 +00:31:33,590 --> 00:31:34,730 +There is an apple. + +738 +00:31:34,730 --> 00:31:38,880 +How about maybe planet Earth +up in the sky up there? + +739 +00:31:38,880 --> 00:31:40,560 +Or Mars or something here? + +740 +00:31:40,560 --> 00:31:43,560 +And you can see that it is generating JSON + +741 +00:31:43,560 --> 00:31:45,379 +that represents our whole document. + +742 +00:31:45,379 --> 00:31:47,345 +So that was super easy + +743 +00:31:47,345 --> 00:31:50,213 +to be able to generate JSON like that. + +744 +00:31:50,213 --> 00:31:53,580 +And now, we're going to do +another super easy thing is, + +745 +00:31:53,580 --> 00:31:57,250 +we're gonna throw that +JSON into UserDefaults + +746 +00:31:57,250 --> 00:32:00,310 +as a way of making our document permanent. + +747 +00:32:00,310 --> 00:32:03,050 +Now, again, we don't have +multiple documents yet, + +748 +00:32:03,050 --> 00:32:04,305 +we can't name documents, + +749 +00:32:04,305 --> 00:32:07,040 +we really should be putting +them in the file system + +750 +00:32:07,040 --> 00:32:09,960 +or even in iCloud or something +like that, but for now, + +751 +00:32:09,960 --> 00:32:12,883 +let's just make it persist +so that when we quit, + +752 +00:32:12,883 --> 00:32:17,883 +and then we go back, we don't +lose our beautiful images. + +753 +00:32:19,130 --> 00:32:19,963 +Now how're we gonna do that? + +754 +00:32:19,963 --> 00:32:21,370 +So I'm gonna stop printing here, + +755 +00:32:21,370 --> 00:32:24,660 +I'm just gonna say UserDefault.standard, + +756 +00:32:24,660 --> 00:32:28,260 +that's the standard UserDefaults database. + +757 +00:32:28,260 --> 00:32:30,210 +You can have others, but +that's the standard one, + +758 +00:32:30,210 --> 00:32:32,652 +we use that 99% of the time. + +759 +00:32:32,652 --> 00:32:37,652 +Set this EmojiArt JSON +value for a certain key, + +760 +00:32:39,950 --> 00:32:41,300 +and you'll remember that from the slides, + +761 +00:32:41,300 --> 00:32:43,480 +that UserDefaults is like a Dictionary, + +762 +00:32:43,480 --> 00:32:45,220 +feels like a Dictionary. + +763 +00:32:45,220 --> 00:32:46,620 +Now you just have to specify a key, + +764 +00:32:46,620 --> 00:32:49,630 +I'll say EmojiArtDocument dot, + +765 +00:32:49,630 --> 00:32:53,440 +this is like an untitled +document or something. + +766 +00:32:53,440 --> 00:32:54,639 +This key can be anything, + +767 +00:32:54,639 --> 00:32:57,990 +we tend to put something +like the class name + +768 +00:32:57,990 --> 00:33:00,130 +or the struct name at the beginning of it, + +769 +00:33:00,130 --> 00:33:02,620 +just because this UserDefaults standard + +770 +00:33:02,620 --> 00:33:03,830 +is used for a whole app, + +771 +00:33:03,830 --> 00:33:07,020 +we might have other structs +that wanna be storing things + +772 +00:33:07,020 --> 00:33:09,880 +in UserDefaults, and we +don't want their keys + +773 +00:33:09,880 --> 00:33:12,193 +to collide with ours. + +774 +00:33:13,170 --> 00:33:16,380 +And that's it, that's going +to write this thing in there. + +775 +00:33:16,380 --> 00:33:17,958 +Notice this is a Data, + +776 +00:33:17,958 --> 00:33:20,970 +and it knows that, this UserDefaults + +777 +00:33:20,970 --> 00:33:22,360 +knows how to put in Datas, + +778 +00:33:22,360 --> 00:33:24,900 +and Strings, and Dates, +and Ints, and Floats, + +779 +00:33:24,900 --> 00:33:26,900 +and Arrays of those things, + +780 +00:33:26,900 --> 00:33:27,753 +and Dictionaries of those things. + +781 +00:33:27,753 --> 00:33:28,605 +And that's it. + +782 +00:33:28,605 --> 00:33:30,610 +It also knows how to handle an Optional, + +783 +00:33:30,610 --> 00:33:31,640 +because this is an Optional. + +784 +00:33:31,640 --> 00:33:33,600 +If I say set, and this is nil, + +785 +00:33:33,600 --> 00:33:36,610 +it'll just clear out +anything for this key. + +786 +00:33:36,610 --> 00:33:38,500 +Now, we wanna get it out. + +787 +00:33:38,500 --> 00:33:40,790 +How do we get that thing out? + +788 +00:33:40,790 --> 00:33:42,440 +Well, back in our EmojiArt, + +789 +00:33:42,440 --> 00:33:45,028 +we know how to encode ourself as a JSON. + +790 +00:33:45,028 --> 00:33:48,714 +But we need some code over +here to decode ourself. + +791 +00:33:48,714 --> 00:33:51,090 +Let me do that with an init. + +792 +00:33:51,090 --> 00:33:51,923 +I'm gonna have an init + +793 +00:33:51,923 --> 00:33:55,024 +that takes a JSON Data as an argument, + +794 +00:33:55,024 --> 00:33:59,012 +and tries to look at +this Data and decode it + +795 +00:33:59,012 --> 00:34:00,873 +to be an EmojiArt. + +796 +00:34:01,850 --> 00:34:03,410 +So, how would we do that? + +797 +00:34:03,410 --> 00:34:07,110 +I'm just gonna say if this JSON +Data does not equal to nil, + +798 +00:34:07,110 --> 00:34:09,337 +I obviously can't decode nil, + +799 +00:34:09,337 --> 00:34:14,042 +then I'm going to let a new +EmojiArt that I'm gonna create + +800 +00:34:14,042 --> 00:34:19,042 +equal trying to use a JSONDecoder +to decode an EmojiArt. + +801 +00:34:24,020 --> 00:34:28,190 +And here I'm specifying the +type of thing I want to decode, + +802 +00:34:28,190 --> 00:34:29,680 +and when we specify type, remember, + +803 +00:34:29,680 --> 00:34:34,552 +we put .self like URL.self we +did for the drop last time. + +804 +00:34:34,552 --> 00:34:38,063 +And I'm gonna do this from +the JSON that was passed in. + +805 +00:34:38,063 --> 00:34:40,840 +And this is either gonna work or not. + +806 +00:34:40,840 --> 00:34:43,599 +It also has a try, just +like this had a try, + +807 +00:34:43,599 --> 00:34:46,680 +and the Data contentsOf had a try. + +808 +00:34:46,680 --> 00:34:48,560 +If just fails, it's gonna return nil. + +809 +00:34:48,560 --> 00:34:50,800 +So this if let is just gonna do nothing, + +810 +00:34:50,800 --> 00:34:52,340 +or we won't get in here. + +811 +00:34:52,340 --> 00:34:56,340 +But if this doesn't fail, +now I have a new EmojiArt. + +812 +00:34:56,340 --> 00:34:59,580 +So now I kinda wanna replace my whole self + +813 +00:34:59,580 --> 00:35:02,364 +with this new EmojiArt, 'cause +I'm initializing myself, + +814 +00:35:02,364 --> 00:35:05,240 +and believe it or not, for +a value type you can say, + +815 +00:35:05,240 --> 00:35:07,430 +self equals something. + +816 +00:35:07,430 --> 00:35:09,790 +You are allowed, with a value type, + +817 +00:35:09,790 --> 00:35:11,980 +to assign something to self, + +818 +00:35:11,980 --> 00:35:14,670 +and it'll replace the whole thing. + +819 +00:35:14,670 --> 00:35:16,770 +Can do it with enums too. + +820 +00:35:16,770 --> 00:35:18,550 +And that's great, that's +exactly what I want. + +821 +00:35:18,550 --> 00:35:19,383 +I'm initializing. + +822 +00:35:19,383 --> 00:35:22,250 +I'm just gonna set myself +equal to whatever EmojiArt + +823 +00:35:22,250 --> 00:35:25,563 +I was able to decode from +the JSON that you gave me. + +824 +00:35:26,500 --> 00:35:29,156 +But, what if I can't decode it though? + +825 +00:35:29,156 --> 00:35:31,099 +If I don't do anything here, + +826 +00:35:31,099 --> 00:35:34,240 +I'm gonna get a blank EmojiArtDocument. + +827 +00:35:34,240 --> 00:35:36,640 +'Cause I won't have +initialized any of these + +828 +00:35:36,640 --> 00:35:38,650 +to something different +than their defaults, which, + +829 +00:35:38,650 --> 00:35:40,920 +this one is nil, and +this is an empty Array, + +830 +00:35:40,920 --> 00:35:43,219 +so I'd get a blank EmojiArtDocument. + +831 +00:35:43,219 --> 00:35:45,890 +But, I don't think +that's what I want here. + +832 +00:35:45,890 --> 00:35:47,600 +If someone asked me to create + +833 +00:35:47,600 --> 00:35:50,080 +an EmojiArtDocument with JSON, + +834 +00:35:50,080 --> 00:35:53,550 +and I'm unable to do it for some reason, + +835 +00:35:53,550 --> 00:35:56,730 +I really need to let them know. + +836 +00:35:56,730 --> 00:35:57,860 +And, the way I'm gonna do that + +837 +00:35:57,860 --> 00:36:00,550 +is with a failable initializer. + +838 +00:36:00,550 --> 00:36:03,630 +If you put question mark right after init, + +839 +00:36:03,630 --> 00:36:05,870 +then when people call this initializer, + +840 +00:36:05,870 --> 00:36:08,228 +if this initializer returns nil, + +841 +00:36:08,228 --> 00:36:11,980 +then they'll get nil back as the object + +842 +00:36:11,980 --> 00:36:14,110 +they were trying to create. + +843 +00:36:14,110 --> 00:36:16,220 +And that really is gonna send the message, + +844 +00:36:16,220 --> 00:36:19,700 +I tried to create EmojiArt +with the JSON, but I couldn't. + +845 +00:36:19,700 --> 00:36:21,610 +So a failable initializer, really easy, + +846 +00:36:21,610 --> 00:36:25,350 +you just put question, +return nil whenever you fail, + +847 +00:36:25,350 --> 00:36:26,930 +and then people are creating you, + +848 +00:36:26,930 --> 00:36:28,600 +they have to check for nil, + +849 +00:36:28,600 --> 00:36:30,020 +because you're returning, essentially, + +850 +00:36:30,020 --> 00:36:32,483 +an Optional version of EmojiArt here. + +851 +00:36:33,427 --> 00:36:35,440 +Now we added an init here, + +852 +00:36:35,440 --> 00:36:37,054 +and I don't know if +you remember the rules? + +853 +00:36:37,054 --> 00:36:40,840 +But if you add an init, then +you lose your free init, + +854 +00:36:40,840 --> 00:36:44,090 +the free init that +specifies each argument. + +855 +00:36:44,090 --> 00:36:45,270 +These all have defaults, + +856 +00:36:45,270 --> 00:36:47,240 +so you could say init with no arguments, + +857 +00:36:47,240 --> 00:36:49,170 +which is what we do over here, actually, + +858 +00:36:49,170 --> 00:36:51,950 +we created an EmojiArt +empty with no arguments. + +859 +00:36:51,950 --> 00:36:54,551 +We lost that init, so +we have to add it back. + +860 +00:36:54,551 --> 00:36:57,620 +So, an init with no arguments +does nothing in our structs, + +861 +00:36:57,620 --> 00:37:00,943 +it just takes these default +values and uses them. + +862 +00:37:02,920 --> 00:37:06,644 +So now we have a way of +creating an EmojiArtDocument + +863 +00:37:06,644 --> 00:37:10,660 +from this JSON data, so +let's use that over here. + +864 +00:37:10,660 --> 00:37:13,738 +Instead of doing this, where +we create an empty one, + +865 +00:37:13,738 --> 00:37:16,307 +I'm going to have an init for my document. + +866 +00:37:16,307 --> 00:37:20,390 +And in my init, I'm just +gonna set my EmojiArt equal to + +867 +00:37:20,390 --> 00:37:23,423 +the EmojiArt that I get +from passing the JSON + +868 +00:37:23,423 --> 00:37:26,220 +that I get out of UserDefaults. + +869 +00:37:26,220 --> 00:37:28,649 +So I'm gonna use my standard UserDefaults, + +870 +00:37:28,649 --> 00:37:33,630 +this time I'm gonna ask for +a Data for that same key. + +871 +00:37:33,630 --> 00:37:38,630 +Now, I could just copy and +paste this down to here, + +872 +00:37:39,000 --> 00:37:40,560 +but that's a dangerous move, + +873 +00:37:40,560 --> 00:37:43,850 +if I miss a character or +whatever, then these won't match. + +874 +00:37:43,850 --> 00:37:46,000 +So let's be good programmers and instead, + +875 +00:37:46,000 --> 00:37:47,890 +create a little static var. + +876 +00:37:47,890 --> 00:37:50,203 +I'm gonna call it untitled. + +877 +00:37:51,610 --> 00:37:56,610 +Lets make it private static let +untitled equals that String, + +878 +00:37:59,890 --> 00:38:02,514 +and then I'll use that down here, + +879 +00:38:02,514 --> 00:38:05,333 +EmojiArtDocument.untitled. + +880 +00:38:06,250 --> 00:38:09,260 +This way I'm guaranteed +that whatever I'm saving out + +881 +00:38:09,260 --> 00:38:11,623 +is the same key I'm +using to get it back in. + +882 +00:38:12,720 --> 00:38:16,410 +By the way, once we load +this EmojiArt back up, + +883 +00:38:16,410 --> 00:38:20,079 +we're for sure going to want +to fetch our background image, + +884 +00:38:20,079 --> 00:38:22,760 +because your EmojiArtDocument +doesn't store the image, + +885 +00:38:22,760 --> 00:38:23,920 +just the URL. + +886 +00:38:23,920 --> 00:38:26,210 +So we gotta go back out on the Internet + +887 +00:38:26,210 --> 00:38:29,330 +and get the image data when we load it up. + +888 +00:38:29,330 --> 00:38:30,480 +Now we're still having an error here, + +889 +00:38:30,480 --> 00:38:33,600 +value of Optional type EmojiArt, + +890 +00:38:33,600 --> 00:38:38,600 +EmojiArt Optional must be +unwrapped to a type EmojiArt. + +891 +00:38:39,379 --> 00:38:40,320 +And that makes sense, right? + +892 +00:38:40,320 --> 00:38:44,957 +Because this is a failable +initializer, it could return nil. + +893 +00:38:44,957 --> 00:38:47,320 +EmojiArt up here can't take nil, + +894 +00:38:47,320 --> 00:38:49,700 +it's not an Optional EmojiArt. + +895 +00:38:49,700 --> 00:38:52,220 +So what I'm gonna do here +is, if it returns nil, + +896 +00:38:52,220 --> 00:38:54,470 +I'm gonna create a blank document. + +897 +00:38:54,470 --> 00:38:56,170 +So at least we have some document. + +898 +00:38:57,340 --> 00:38:59,313 +Okay, let's fire this thing up. + +899 +00:39:00,236 --> 00:39:01,069 +Let's see if it works. + +900 +00:39:01,069 --> 00:39:03,470 +Okay, we start out with a +blank document, of course, + +901 +00:39:03,470 --> 00:39:06,170 +that's this question mark +question mark blank document + +902 +00:39:06,170 --> 00:39:09,421 +because we couldn't load +anything up from UserDefaults + +903 +00:39:09,421 --> 00:39:11,820 +at the start, there was nothing in there. + +904 +00:39:11,820 --> 00:39:15,357 +But if we start building our +thing here, let's do that. + +905 +00:39:15,357 --> 00:39:18,280 +Put our apples back in here. + +906 +00:39:18,280 --> 00:39:22,174 +Put our Earth up in the sky up here. + +907 +00:39:22,174 --> 00:39:26,610 +This is hopefully writing +out the JSON as we speak + +908 +00:39:26,610 --> 00:39:28,270 +to our UserDefaults. + +909 +00:39:28,270 --> 00:39:32,743 +Let's quit, and then run it +again and see what happens. + +910 +00:39:32,743 --> 00:39:34,930 +Woo hoo, there's our document. + +911 +00:39:34,930 --> 00:39:36,791 +Now, sometimes you have +to be a little careful. + +912 +00:39:36,791 --> 00:39:40,490 +If we, I don't know, drop a +baseball in the front yard, + +913 +00:39:40,490 --> 00:39:44,363 +there it is, and now we press +stop, and then we run again, + +914 +00:39:45,950 --> 00:39:47,640 +oh, we lost her baseball. + +915 +00:39:47,640 --> 00:39:49,421 +Why didn't the baseball work? + +916 +00:39:49,421 --> 00:39:52,950 +Well, UserDefaults, when you +put things in UserDefaults, + +917 +00:39:52,950 --> 00:39:55,890 +it doesn't run right out to +the disk and write it out, + +918 +00:39:55,890 --> 00:39:58,290 +it buffers them up and writes them out + +919 +00:39:58,290 --> 00:40:01,015 +at an appropriate time, +when it's convenient. + +920 +00:40:01,015 --> 00:40:04,180 +And, we don't give it a chance to do that + +921 +00:40:04,180 --> 00:40:07,970 +because we picked this baseball +up, we put it down here, + +922 +00:40:07,970 --> 00:40:11,390 +and we hit stop, and that kills our app. + +923 +00:40:11,390 --> 00:40:12,670 +It just kills it. + +924 +00:40:12,670 --> 00:40:15,390 +There's no chance to go +do something like that. + +925 +00:40:15,390 --> 00:40:18,020 +So when you're doing +debugging and you're using, + +926 +00:40:18,020 --> 00:40:19,746 +we got lucky that time, it wrote it out. + +927 +00:40:19,746 --> 00:40:22,830 +When you're doing that, +one thing you wanna do is, + +928 +00:40:22,830 --> 00:40:25,540 +when you have a change +and you want UserDefaults + +929 +00:40:25,540 --> 00:40:29,110 +to write things out, just +switch to another app. + +930 +00:40:29,110 --> 00:40:31,240 +Here I'm gonna switch to the files app. + +931 +00:40:31,240 --> 00:40:33,110 +Doesn't really matter, and switch back. + +932 +00:40:33,110 --> 00:40:34,600 +Because when you switch to another app, + +933 +00:40:34,600 --> 00:40:37,740 +UserDefaults is always gonna +write the database out. + +934 +00:40:37,740 --> 00:40:42,263 +That way when you quit, and +you come back, it's there. + +935 +00:40:43,750 --> 00:40:45,530 +That's all I really wanted to talk about + +936 +00:40:45,530 --> 00:40:47,611 +in terms of storage for now, + +937 +00:40:47,611 --> 00:40:49,600 +and we're gonna be working on this more + +938 +00:40:49,600 --> 00:40:50,960 +as the quarter goes on. + +939 +00:40:50,960 --> 00:40:54,690 +But the next thing I wanna +talk about is gestures. + +940 +00:40:54,690 --> 00:40:59,004 +What I wanna be able to do +here is to zoom in and out + +941 +00:40:59,004 --> 00:41:00,950 +on my document. + +942 +00:41:00,950 --> 00:41:01,783 +And I'll show you why. + +943 +00:41:01,783 --> 00:41:03,840 +Here's another image down here. + +944 +00:41:03,840 --> 00:41:08,840 +Let's go ahead and drag +and drop this image in here + +945 +00:41:09,110 --> 00:41:10,193 +and see what happens. + +946 +00:41:11,280 --> 00:41:12,950 +Whoa. + +947 +00:41:12,950 --> 00:41:16,620 +Okay, it definitely put that +image in here, but it's huge. + +948 +00:41:16,620 --> 00:41:18,600 +This is just a huge image. + +949 +00:41:18,600 --> 00:41:22,270 +And so, I really want to +be able to zoom in here. + +950 +00:41:22,270 --> 00:41:24,610 +I'm holding down option by +the way, in the simulator, + +951 +00:41:24,610 --> 00:41:28,350 +that's how you can simulate +two fingers being down. + +952 +00:41:28,350 --> 00:41:31,493 +And I really wanna zoom in and +see the whole picture here. + +953 +00:41:31,493 --> 00:41:33,870 +There's another horse, whole +bunch of other animals, + +954 +00:41:33,870 --> 00:41:36,343 +I wanna be able to see these things. + +955 +00:41:37,370 --> 00:41:38,330 +Now, I don't know if you know this, + +956 +00:41:38,330 --> 00:41:40,532 +another terrible problem +with this huge image, + +957 +00:41:40,532 --> 00:41:44,240 +it blasted our emoji palette. + +958 +00:41:44,240 --> 00:41:46,290 +We can't even add more emojis, + +959 +00:41:46,290 --> 00:41:48,650 +they all got wiped out up here. + +960 +00:41:48,650 --> 00:41:50,862 +This is somehow drawing outside + +961 +00:41:50,862 --> 00:41:52,908 +of where it's supposed to draw. + +962 +00:41:52,908 --> 00:41:55,200 +And that's actually normal in SwiftUI. + +963 +00:41:55,200 --> 00:41:57,760 +The default in SwiftUI is for Views + +964 +00:41:57,760 --> 00:42:00,985 +to be able to draw outside +of their boundaries. + +965 +00:42:00,985 --> 00:42:03,884 +So if we wanna keep a View +inside its boundaries, + +966 +00:42:03,884 --> 00:42:06,590 +we have to do a modifier on it. + +967 +00:42:06,590 --> 00:42:09,087 +So let's start with that, +let's get our pallet back + +968 +00:42:09,087 --> 00:42:10,563 +before we do anything. + +969 +00:42:11,450 --> 00:42:13,918 +The modifier we use, +really, really simple. + +970 +00:42:13,918 --> 00:42:18,760 +Gonna put it, let's put it +on the ZStack right here. + +971 +00:42:18,760 --> 00:42:20,879 +So here's our ZStack of stuff. + +972 +00:42:20,879 --> 00:42:23,917 +It's called .clipped + +973 +00:42:23,917 --> 00:42:26,060 +.clipped just means +all the drawing it does + +974 +00:42:26,060 --> 00:42:29,500 +is gonna be clipped to +the bounds of the View. + +975 +00:42:29,500 --> 00:42:32,280 +By the way, while I'm here, +let's move this stuff, + +976 +00:42:32,280 --> 00:42:34,555 +the edges stuff, and the dropping stuff, + +977 +00:42:34,555 --> 00:42:37,453 +let's move that down here as well. + +978 +00:42:38,452 --> 00:42:40,810 +Reason I'm moving that out here is, + +979 +00:42:40,810 --> 00:42:43,610 +these do semantically apply to the ZStack, + +980 +00:42:43,610 --> 00:42:45,940 +we do want the ZStack going +all the way to the edges, + +981 +00:42:45,940 --> 00:42:48,187 +and we wanna be able to +drop anywhere in the ZStack. + +982 +00:42:48,187 --> 00:42:49,942 +And it cleans up this in here + +983 +00:42:49,942 --> 00:42:53,807 +so it's much cleaner of +what's going on in here. + +984 +00:42:53,807 --> 00:42:56,661 +Although, this is not +very clean right here. + +985 +00:42:56,661 --> 00:42:59,350 +Let's go make sure this clipped worked, + +986 +00:42:59,350 --> 00:43:00,390 +then we're gonna run back in here + +987 +00:43:00,390 --> 00:43:02,623 +and fix this not so +clean code right there. + +988 +00:43:07,860 --> 00:43:09,460 +All right, here's our big thing. + +989 +00:43:09,460 --> 00:43:12,160 +And it's still big, so we +still need our gesture, + +990 +00:43:12,160 --> 00:43:15,897 +but look, woo, we still +have our various emoji + +991 +00:43:15,897 --> 00:43:18,180 +and we can still drop them in there. + +992 +00:43:18,180 --> 00:43:19,660 +All right, let's go +back and clean that code + +993 +00:43:19,660 --> 00:43:20,580 +I was talking about. + +994 +00:43:20,580 --> 00:43:24,000 +This code, why is this not really clean? + +995 +00:43:24,000 --> 00:43:27,900 +In SwiftUI, it's all really +about breaking these Views down + +996 +00:43:27,900 --> 00:43:30,490 +into small little Views. + +997 +00:43:30,490 --> 00:43:34,230 +Especially when you have a +semantic boundary of a View + +998 +00:43:34,230 --> 00:43:35,812 +like we have here. + +999 +00:43:35,812 --> 00:43:38,220 +What is this code all about? + +1000 +00:43:38,220 --> 00:43:40,864 +This code is all just about +showing this background image, + +1001 +00:43:40,864 --> 00:43:43,548 +but unfortunately it might be nil, + +1002 +00:43:43,548 --> 00:43:45,460 +so we have to check for that. + +1003 +00:43:45,460 --> 00:43:47,230 +That's all we're doing here. + +1004 +00:43:47,230 --> 00:43:49,730 +And, if someone's +reading through our code, + +1005 +00:43:49,730 --> 00:43:51,560 +they're having to pass a lot of code here + +1006 +00:43:51,560 --> 00:43:53,960 +just to realize that +we're showing an image + +1007 +00:43:53,960 --> 00:43:55,173 +that might be Optional. + +1008 +00:43:56,040 --> 00:43:57,835 +We shouldn't ask readers of our code + +1009 +00:43:57,835 --> 00:44:02,450 +to have this much trouble +understanding what's going on. + +1010 +00:44:02,450 --> 00:44:04,810 +I'm gonna make another sub-View, + +1011 +00:44:04,810 --> 00:44:06,710 +and this is the way we break this down. + +1012 +00:44:06,710 --> 00:44:09,410 +We just make, either +called functions and vars + +1013 +00:44:09,410 --> 00:44:11,460 +to put our View somewhere else, + +1014 +00:44:11,460 --> 00:44:15,480 +or we can make new Views, +like we made CardView. + +1015 +00:44:15,480 --> 00:44:18,387 +So I'm gonna make another +View down here, I'm gonna say + +1016 +00:44:18,387 --> 00:44:20,710 +struct. I'm gonna call it OptionalImage. + +1017 +00:44:20,710 --> 00:44:25,630 +And it's just gonna be +a View that takes a var, + +1018 +00:44:25,630 --> 00:44:29,900 +which is a UIImage, Optional UIImage. + +1019 +00:44:29,900 --> 00:44:33,570 +And then my var body is gonna +return some View, as always. + +1020 +00:44:33,570 --> 00:44:35,110 +I'm just gonna put this code in there, + +1021 +00:44:35,110 --> 00:44:38,150 +so I'm gonna go grab this code, +let's get this outta here. + +1022 +00:44:38,150 --> 00:44:41,860 +Cut, just down in here, paste. + +1023 +00:44:41,860 --> 00:44:43,289 +Of course, I'm using this uiImage + +1024 +00:44:43,289 --> 00:44:45,737 +instead of this backgroundImage. + +1025 +00:44:51,753 --> 00:44:52,586 +That's it. + +1026 +00:44:52,586 --> 00:44:56,112 +So I've just created this +little utility thing right here, + +1027 +00:44:56,112 --> 00:45:01,112 +and all it does is handle a +UIImage that might be nil. + +1028 +00:45:01,460 --> 00:45:04,620 +And now, my code up here +turns from all that mess + +1029 +00:45:04,620 --> 00:45:09,620 +to just OptionalImage of a +self.document.backgroundImage. + +1030 +00:45:12,580 --> 00:45:15,890 +Much cleaner up here to +understand what's going on. + +1031 +00:45:15,890 --> 00:45:19,840 +Especially looking at +this ZStack right here, + +1032 +00:45:19,840 --> 00:45:21,830 +it's clear that this +is my background image + +1033 +00:45:21,830 --> 00:45:23,550 +and these are my emojis. + +1034 +00:45:23,550 --> 00:45:25,510 +Much simpler. + +1035 +00:45:25,510 --> 00:45:26,674 +Now this OptionalImage, + +1036 +00:45:26,674 --> 00:45:30,890 +this has nothing to do +with EmojiArt, whatsoever. + +1037 +00:45:30,890 --> 00:45:32,117 +So I'm gonna take it outta here + +1038 +00:45:32,117 --> 00:45:34,400 +and put it in its own file. + +1039 +00:45:34,400 --> 00:45:36,090 +Which, you really wanna do that, + +1040 +00:45:36,090 --> 00:45:37,750 +when you have something that's unrelated, + +1041 +00:45:37,750 --> 00:45:41,880 +don't bury those things +inside unrelated code. + +1042 +00:45:41,880 --> 00:45:46,180 +So this is called OptionalImage, +put in its own file. + +1043 +00:45:46,180 --> 00:45:49,560 +And this file that I've +created right here, + +1044 +00:45:49,560 --> 00:45:51,263 +I might well use this, + +1045 +00:45:51,263 --> 00:45:54,560 +pick it up and drag it into +some other app that I'm writing, + +1046 +00:45:54,560 --> 00:45:57,980 +it's quite a useful little View here, + +1047 +00:45:57,980 --> 00:46:00,333 +and quite reusable in that sense. + +1048 +00:46:02,148 --> 00:46:03,740 +Wanted to take that little detour, + +1049 +00:46:03,740 --> 00:46:07,760 +just because I didn't want +you to be creating these Views + +1050 +00:46:07,760 --> 00:46:10,020 +that just had hundreds +of lines of code in here, + +1051 +00:46:10,020 --> 00:46:12,970 +and then just completely +un-understandable. + +1052 +00:46:12,970 --> 00:46:15,770 +Okay, back to what we wanna do which is, + +1053 +00:46:15,770 --> 00:46:20,707 +we want to be able to, in +our EmojiArt over here, + +1054 +00:46:20,707 --> 00:46:24,560 +zoom in on these huge images so we can see + +1055 +00:46:24,560 --> 00:46:25,763 +what's going on there. + +1056 +00:46:26,600 --> 00:46:31,356 +We're gonna do that by +introducing a new piece of @State + +1057 +00:46:31,356 --> 00:46:36,356 +into our View, which I'm +gonna call our zoomScale. + +1058 +00:46:36,750 --> 00:46:39,920 +This is just @State because +it's only going to affect + +1059 +00:46:39,920 --> 00:46:41,260 +the way our View looks. + +1060 +00:46:41,260 --> 00:46:45,150 +This has nothing to do with +our EmojiArt document itself, + +1061 +00:46:45,150 --> 00:46:49,530 +it's purely a UI visual +thing, and it's temporary. + +1062 +00:46:49,530 --> 00:46:50,580 +As we zoom in and out, + +1063 +00:46:50,580 --> 00:46:54,147 +it's just showing us how +much zooming there is. + +1064 +00:46:54,147 --> 00:46:56,031 +It's just gonna be a CGFloat. + +1065 +00:46:56,031 --> 00:46:57,481 +I'm gonna start out equal 1.0. + +1066 +00:46:58,550 --> 00:47:00,410 +And this is room scale is gonna be + +1067 +00:47:00,410 --> 00:47:04,704 +how much were zoomed in or +out on our entire document. + +1068 +00:47:04,704 --> 00:47:07,300 +zoomScale 1.0 means our document is + +1069 +00:47:07,300 --> 00:47:11,530 +whatever the size of its +background URL's image is. + +1070 +00:47:11,530 --> 00:47:14,410 +But 2.0 means it's twice as big as that. + +1071 +00:47:14,410 --> 00:47:16,993 +And .5 means it's half as big as that. + +1072 +00:47:17,930 --> 00:47:19,940 +The first thing I'm gonna +do with this zoomScale + +1073 +00:47:19,940 --> 00:47:22,730 +is go apply it to everywhere in my View + +1074 +00:47:22,730 --> 00:47:24,119 +where it would matter. + +1075 +00:47:24,119 --> 00:47:29,100 +So, for example, my background +image, clearly that matters, + +1076 +00:47:29,100 --> 00:47:33,947 +I want to scaleEffect +it to be our zoomScale. + +1077 +00:47:35,240 --> 00:47:37,750 +So that's gonna make my +background image the right size. + +1078 +00:47:37,750 --> 00:47:41,570 +Of course, my emojis here +also need to get bigger + +1079 +00:47:41,570 --> 00:47:43,030 +when I zoom in. + +1080 +00:47:43,030 --> 00:47:44,120 +So that's their font. + +1081 +00:47:44,120 --> 00:47:45,910 +So let's go down to +their font, here it is. + +1082 +00:47:45,910 --> 00:47:47,810 +We're seeing their font to this font size, + +1083 +00:47:47,810 --> 00:47:52,800 +we gotta zoom that up by our zoomScale. + +1084 +00:47:52,800 --> 00:47:54,120 +And the other thing we need to do is + +1085 +00:47:54,120 --> 00:47:57,704 +every time we're converting +from this iOS coordinate system, + +1086 +00:47:57,704 --> 00:48:00,090 +which is (0, 0) in the upper left, + +1087 +00:48:00,090 --> 00:48:02,060 +to the EmojiArt coordinate system, + +1088 +00:48:02,060 --> 00:48:03,920 +which is (0, 0) in the middle, + +1089 +00:48:03,920 --> 00:48:05,580 +we have to be careful because + +1090 +00:48:05,580 --> 00:48:07,240 +when things are far away from the middle, + +1091 +00:48:07,240 --> 00:48:09,760 +when they're zoomed up, they're +very far from the middle, + +1092 +00:48:09,760 --> 00:48:11,000 +so it effects that. + +1093 +00:48:11,000 --> 00:48:13,389 +So where are the two +places that we convert + +1094 +00:48:13,389 --> 00:48:14,969 +those coordinate systems? + +1095 +00:48:14,969 --> 00:48:17,710 +One is here when we're dropping. + +1096 +00:48:17,710 --> 00:48:20,330 +And also here where we're +positioning the emojis, + +1097 +00:48:20,330 --> 00:48:22,560 +this place where we're +going through the emojis + +1098 +00:48:22,560 --> 00:48:23,820 +and putting them down. + +1099 +00:48:23,820 --> 00:48:26,020 +Well, obviously we're +being told where they are + +1100 +00:48:26,020 --> 00:48:29,500 +in EmojiArt's (0, 0) +centered coordinate system, + +1101 +00:48:29,500 --> 00:48:30,950 +we need to convert them. + +1102 +00:48:30,950 --> 00:48:33,261 +So we need to fix both of these cases. + +1103 +00:48:33,261 --> 00:48:37,410 +Our location of the drop +is now just going to be + +1104 +00:48:37,410 --> 00:48:42,410 +the location it was, but +divided by the zoomScale. + +1105 +00:48:43,790 --> 00:48:44,920 +Same thing with y. + +1106 +00:48:44,920 --> 00:48:46,120 +So that fixes + +1107 +00:48:46,120 --> 00:48:49,720 +the coordinate system +transformation for drops. + +1108 +00:48:49,720 --> 00:48:52,290 +And for position, kinda +have this embedded here, + +1109 +00:48:52,290 --> 00:48:53,580 +let's clean this up a little bit, + +1110 +00:48:53,580 --> 00:48:57,177 +I'm gonna say my location +is my emoji's location, + +1111 +00:48:57,177 --> 00:49:02,177 +and I'm gonna modify the +location to be this essentially, + +1112 +00:49:03,530 --> 00:49:04,900 +except for that. + +1113 +00:49:04,900 --> 00:49:07,083 +Now I put it in location. + +1114 +00:49:10,170 --> 00:49:11,790 +I'm gonna return that location + +1115 +00:49:11,790 --> 00:49:12,920 +and by splitting that out, + +1116 +00:49:12,920 --> 00:49:15,621 +it makes it really easy for us to add this + +1117 +00:49:15,621 --> 00:49:19,210 +little zoomScale modification +to it right before. + +1118 +00:49:19,210 --> 00:49:20,043 +So I'm gonna say + +1119 +00:49:20,043 --> 00:49:24,710 +location equals CGPoint +location.x times our zoomScale, + +1120 +00:49:26,615 --> 00:49:31,615 +and the y is location.y +times our zoomScale. + +1121 +00:49:31,730 --> 00:49:33,940 +That seems to be all the places I think + +1122 +00:49:33,940 --> 00:49:36,350 +that our zoomScale would apply. + +1123 +00:49:36,350 --> 00:49:39,790 +We're zooming our document in nicely. + +1124 +00:49:39,790 --> 00:49:42,060 +What gesture are we gonna use? + +1125 +00:49:42,060 --> 00:49:43,820 +Well, we wanna pinch. + +1126 +00:49:43,820 --> 00:49:46,204 +But I'm gonna have another +gesture that's kinda fun, + +1127 +00:49:46,204 --> 00:49:48,290 +which is double tap. + +1128 +00:49:48,290 --> 00:49:51,214 +And double tap is going +to zoom my entire document + +1129 +00:49:51,214 --> 00:49:54,365 +to exactly fit the space available. + +1130 +00:49:54,365 --> 00:49:56,630 +We get a certain amount +of space for our document, + +1131 +00:49:56,630 --> 00:50:00,560 +depending on where our app is in the UI, + +1132 +00:50:00,560 --> 00:50:03,170 +and I'm gonna zoom it to fit that. + +1133 +00:50:03,170 --> 00:50:06,420 +So let's create a new private func here, + +1134 +00:50:06,420 --> 00:50:08,887 +that I'm gonna call zoomToFit. + +1135 +00:50:08,887 --> 00:50:12,453 +And it's gonna take the +image to have it fit. + +1136 +00:50:14,060 --> 00:50:16,580 +Might be nil 'cause our +background image can be nil, + +1137 +00:50:16,580 --> 00:50:17,973 +in some size. + +1138 +00:50:19,280 --> 00:50:22,113 +And it's just going to set our zoomScale. + +1139 +00:50:22,113 --> 00:50:24,393 +It's gonna set the zoomScale to fit. + +1140 +00:50:25,240 --> 00:50:28,010 +Now, I'm only gonna do +this if we have an image. + +1141 +00:50:28,010 --> 00:50:30,540 +We have an image, I'm not +gonna touch the zoomScale, + +1142 +00:50:30,540 --> 00:50:33,940 +and I'm also only gonna do this +if that image has some size, + +1143 +00:50:33,940 --> 00:50:35,520 +so I'm gonna check to make sure + +1144 +00:50:35,520 --> 00:50:38,370 +that the image.size.width +is greater than zero, + +1145 +00:50:38,370 --> 00:50:42,100 +and that the image.size.height +is greater than zero. + +1146 +00:50:42,100 --> 00:50:44,480 +So, we have some image of some size + +1147 +00:50:44,480 --> 00:50:46,530 +and now we're going to zoomToFit it. + +1148 +00:50:46,530 --> 00:50:50,760 +Now we could zoom it based +on the horizontal zoom + +1149 +00:50:50,760 --> 00:50:55,160 +by saying size.width divided +by images.size.width. + +1150 +00:50:55,160 --> 00:50:57,900 +Or we could do it by the vertical zooming, + +1151 +00:50:57,900 --> 00:51:00,080 +which would be the size.height divided by + +1152 +00:51:00,080 --> 00:51:02,760 +the image.size.height. + +1153 +00:51:02,760 --> 00:51:04,610 +So which of these two should we use, + +1154 +00:51:04,610 --> 00:51:06,560 +the horizontal or the vertical? + +1155 +00:51:06,560 --> 00:51:09,200 +I think we're gonna use +the smaller of the two. + +1156 +00:51:09,200 --> 00:51:12,042 +So I'm gonna set my zoomScale + +1157 +00:51:12,042 --> 00:51:15,930 +equal to the min of the horizontal zoom + +1158 +00:51:15,930 --> 00:51:18,020 +or the vertical zoom. + +1159 +00:51:18,020 --> 00:51:19,250 +So whichever is gonna make it smaller. + +1160 +00:51:19,250 --> 00:51:22,210 +That way the image will +always be fully on screen + +1161 +00:51:22,210 --> 00:51:23,043 +no matter what. + +1162 +00:51:24,180 --> 00:51:25,420 +Almost there. + +1163 +00:51:25,420 --> 00:51:28,430 +Now we just need to add to +the gesture to our Views. + +1164 +00:51:28,430 --> 00:51:30,280 +We just need to mark whichever Views + +1165 +00:51:30,280 --> 00:51:32,720 +we want that double tap to work on, + +1166 +00:51:32,720 --> 00:51:34,330 +to be able to do this. + +1167 +00:51:34,330 --> 00:51:35,560 +So I'm gonna make it + +1168 +00:51:35,560 --> 00:51:39,810 +so that double tapping on the +background here does that. + +1169 +00:51:39,810 --> 00:51:42,132 +So let's go here and add a gesture. + +1170 +00:51:42,132 --> 00:51:45,302 +We do that with the gesture ViewModifier, + +1171 +00:51:45,302 --> 00:51:48,167 +and we just specify the gesture we want. + +1172 +00:51:48,167 --> 00:51:50,260 +Now I'm going to make a little function + +1173 +00:51:50,260 --> 00:51:51,620 +to make that gesture + +1174 +00:51:51,620 --> 00:51:56,620 +called doubleTapToZoom in geometry.size. + +1175 +00:51:57,970 --> 00:51:59,316 +And this function has to return + +1176 +00:51:59,316 --> 00:52:01,702 +something that is some Gesture. + +1177 +00:52:01,702 --> 00:52:05,980 +This gesture only takes a +Gesture as its argument. + +1178 +00:52:05,980 --> 00:52:10,780 +So I'm gonna go down here +and create a private func + +1179 +00:52:10,780 --> 00:52:15,713 +called doubleTapToZoom in size. + +1180 +00:52:15,713 --> 00:52:18,973 +And it has to return some Gesture. + +1181 +00:52:19,910 --> 00:52:24,480 +That's what this ViewModifier +takes, it takes some Gesture. + +1182 +00:52:24,480 --> 00:52:27,330 +So we have to return some Gesture. + +1183 +00:52:27,330 --> 00:52:29,090 +What Gesture are we gonna return? + +1184 +00:52:29,090 --> 00:52:30,540 +Well, we're doing double tap, + +1185 +00:52:30,540 --> 00:52:32,350 +so that is a TapGesture. + +1186 +00:52:33,240 --> 00:52:34,600 +There are a number of Gestures, + +1187 +00:52:34,600 --> 00:52:36,000 +we talked about this in the slides. + +1188 +00:52:36,000 --> 00:52:39,286 +TapGesture is a good one doing double tap. + +1189 +00:52:39,286 --> 00:52:43,583 +In fact, I want a TapGesture +whose count is two. + +1190 +00:52:44,970 --> 00:52:46,370 +And I'm gonna return that. + +1191 +00:52:46,370 --> 00:52:48,291 +But of course, I have to specify, + +1192 +00:52:48,291 --> 00:52:51,640 +when this TapGesture +happens, what am I gonna do? + +1193 +00:52:51,640 --> 00:52:54,592 +In this case I wanna call zoomToFit. + +1194 +00:52:54,592 --> 00:52:58,509 +We do that by the .onEnded +function in Gesture. + +1195 +00:53:00,880 --> 00:53:04,175 +Now .onEnded takes a function to execute + +1196 +00:53:04,175 --> 00:53:07,410 +when this Gesture, whatever it is, + +1197 +00:53:07,410 --> 00:53:09,970 +in this case a double tap, ends. + +1198 +00:53:09,970 --> 00:53:13,520 +So a double tap is when that +second tap finger comes up, + +1199 +00:53:13,520 --> 00:53:16,563 +it ended, and we can do .onEnded here. + +1200 +00:53:17,710 --> 00:53:19,060 +What are we gonna do in here? + +1201 +00:53:19,060 --> 00:53:20,777 +self.zoomToFit. + +1202 +00:53:23,220 --> 00:53:24,190 +And what are we gonna fit? + +1203 +00:53:24,190 --> 00:53:27,527 +We're gonna fit our +document's backgroundImage. + +1204 +00:53:29,460 --> 00:53:32,543 +And the size is the +size that was passed in. + +1205 +00:53:33,790 --> 00:53:34,840 +So let's take a look. + +1206 +00:53:39,170 --> 00:53:40,320 +Here's our huge image. + +1207 +00:53:40,320 --> 00:53:41,760 +I'm gonna double tap. + +1208 +00:53:41,760 --> 00:53:43,410 +Woo, we made it small. + +1209 +00:53:43,410 --> 00:53:46,430 +Let's go for the smaller +image, this little guy. + +1210 +00:53:46,430 --> 00:53:49,248 +It's a really small image, +'cause we're zoomed in right now. + +1211 +00:53:49,248 --> 00:53:50,550 +(vocalizing) + +1212 +00:53:50,550 --> 00:53:52,320 +Now the only thing I don't really like + +1213 +00:53:52,320 --> 00:53:56,430 +about what I've done here is it's jarring. + +1214 +00:53:56,430 --> 00:54:01,430 +And we know that in +mobile apps we want things + +1215 +00:54:01,560 --> 00:54:02,840 +not to jump like that. + +1216 +00:54:02,840 --> 00:54:04,920 +We want some animation. + +1217 +00:54:04,920 --> 00:54:06,110 +So let's throw some animation in here. + +1218 +00:54:06,110 --> 00:54:07,830 +You know how to do that, + +1219 +00:54:07,830 --> 00:54:10,543 +with animation, explicit animation. + +1220 +00:54:11,532 --> 00:54:13,220 +With the zoomToFit in there. + +1221 +00:54:13,220 --> 00:54:14,470 +Let's see how that works. + +1222 +00:54:19,780 --> 00:54:22,283 +Woo, that looks a lot lot better. + +1223 +00:54:23,450 --> 00:54:26,163 +But, I actually think I +notice something weird + +1224 +00:54:26,163 --> 00:54:31,016 +with the emojis there. + +1225 +00:54:31,016 --> 00:54:33,053 +So let's go get the small one here. + +1226 +00:54:34,854 --> 00:54:36,093 +And watch these emojis. + +1227 +00:54:37,090 --> 00:54:39,107 +Ooh, they're kinda jerky. + +1228 +00:54:39,107 --> 00:54:41,110 +Anytime I see in an animation + +1229 +00:54:41,110 --> 00:54:42,512 +I don't really like what I'm seeing, + +1230 +00:54:42,512 --> 00:54:45,300 +I'm gonna go over here +and slow it way down. + +1231 +00:54:45,300 --> 00:54:49,110 +Let's use a linear animation here. + +1232 +00:54:49,110 --> 00:54:51,363 +Duration, let's say 4 seconds. + +1233 +00:54:52,260 --> 00:54:54,413 +And let's just watch that thing in action. + +1234 +00:54:56,291 --> 00:54:59,663 +All right, let's pick up the +bigger one again, here it is. + +1235 +00:55:01,750 --> 00:55:03,330 +Right, now I'm gonna double tap. + +1236 +00:55:03,330 --> 00:55:05,830 +And we're gonna watch these emoji. + +1237 +00:55:05,830 --> 00:55:10,120 +Oh whoa, so the emoji aren't animating, + +1238 +00:55:10,120 --> 00:55:13,110 +they just jumped to the +size they should be. + +1239 +00:55:13,110 --> 00:55:14,920 +And actually, I think +it's even worse than that. + +1240 +00:55:14,920 --> 00:55:17,380 +Let's go and watch them now going bigger, + +1241 +00:55:17,380 --> 00:55:19,290 +ready, ready, watch here. + +1242 +00:55:19,290 --> 00:55:20,240 +Oh, see that? + +1243 +00:55:20,240 --> 00:55:22,130 +They went big and then they got cut off + +1244 +00:55:22,130 --> 00:55:25,600 +because the size of +the View was animating, + +1245 +00:55:25,600 --> 00:55:27,800 +but it hadn't caught +up to how big they are. + +1246 +00:55:28,810 --> 00:55:30,420 +This is a problem. + +1247 +00:55:30,420 --> 00:55:34,940 +We have to somehow animate +the size of this font + +1248 +00:55:34,940 --> 00:55:36,820 +that's being used. + +1249 +00:55:36,820 --> 00:55:38,520 +Well, we know how to do this. + +1250 +00:55:38,520 --> 00:55:41,410 +This is a little bit of +review for you actually. + +1251 +00:55:41,410 --> 00:55:44,250 +How does animation work in SwiftUI? + +1252 +00:55:44,250 --> 00:55:47,480 +It happens with ViewModifiers. + +1253 +00:55:47,480 --> 00:55:49,150 +Now, I'm not gonna go through, + +1254 +00:55:49,150 --> 00:55:50,920 +we're already pressed +for time in this demo, + +1255 +00:55:50,920 --> 00:55:52,850 +so I'm not gonna go +through all the details + +1256 +00:55:52,850 --> 00:55:56,912 +of making our own Animatable +font size ViewModifier, + +1257 +00:55:56,912 --> 00:55:58,220 +but I did do it. + +1258 +00:55:58,220 --> 00:56:01,450 +So let's go over here and drag it in. + +1259 +00:56:01,450 --> 00:56:05,913 +Here is my Animatable modifier. + +1260 +00:56:06,960 --> 00:56:08,810 +I'm gonna take a brief look at this code. + +1261 +00:56:08,810 --> 00:56:11,690 +You can look at it at your leisure later. + +1262 +00:56:11,690 --> 00:56:14,750 +But all it's doing is +essentially making animatableData + +1263 +00:56:14,750 --> 00:56:16,350 +that is the font size. + +1264 +00:56:16,350 --> 00:56:19,087 +So I have this font size, +it's the animatableData, + +1265 +00:56:19,087 --> 00:56:24,087 +and my content is just a Font, +the system font of that size. + +1266 +00:56:24,288 --> 00:56:26,280 +Couldn't be easier. + +1267 +00:56:26,280 --> 00:56:28,297 +I've even made a nice +little extension on View + +1268 +00:56:28,297 --> 00:56:31,660 +that let's me be able to +say .font animatableWithSize + +1269 +00:56:32,530 --> 00:56:36,780 +and give it the size, and it +will automatically modify it. + +1270 +00:56:36,780 --> 00:56:38,820 +This is really easy to apply this. + +1271 +00:56:38,820 --> 00:56:41,060 +Wherever we set the font, +which is right here, + +1272 +00:56:41,060 --> 00:56:45,050 +instead of calling this +self set font for emoji, + +1273 +00:56:45,050 --> 00:56:45,883 +which is down here, + +1274 +00:56:45,883 --> 00:56:49,338 +I'm just gonna take this +size, cut it out of there, + +1275 +00:56:49,338 --> 00:56:53,370 +not gonna need this anymore, +and put it right up in here + +1276 +00:56:53,370 --> 00:56:58,030 +in my new font animatableWithSize. + +1277 +00:56:58,030 --> 00:56:58,863 +There it is. + +1278 +00:57:00,330 --> 00:57:01,703 +That's the size I want. + +1279 +00:57:06,923 --> 00:57:08,390 +And we need self. + +1280 +00:57:08,390 --> 00:57:12,501 +This is going to modify this +Text in an animatable way + +1281 +00:57:12,501 --> 00:57:15,120 +to this new font size. + +1282 +00:57:15,120 --> 00:57:17,903 +And again, can double tap here. + +1283 +00:57:19,160 --> 00:57:21,810 +Okay, it's a little slow, it +looks like it's working there. + +1284 +00:57:21,810 --> 00:57:24,083 +Let's make the really big one over here. + +1285 +00:57:29,470 --> 00:57:32,320 +Okay, watching carefully now, here we go. + +1286 +00:57:32,320 --> 00:57:34,700 +Ooh yeah, looking good. + +1287 +00:57:34,700 --> 00:57:37,260 +Much smoother animation there. + +1288 +00:57:37,260 --> 00:57:40,653 +And, the real test, try the smaller one. + +1289 +00:57:42,470 --> 00:57:47,470 +Ooh, okay, so it looks like our animation + +1290 +00:57:47,730 --> 00:57:49,784 +is working perfectly here. + +1291 +00:57:49,784 --> 00:57:52,233 +Let's go ahead and speed it back up. + +1292 +00:57:54,850 --> 00:57:57,123 +And move on to doing our pinch. + +1293 +00:57:58,150 --> 00:58:02,020 +So the pinch is just a +different kind of gesture. + +1294 +00:58:02,020 --> 00:58:04,820 +And you'll remember from the +slides that we did today, + +1295 +00:58:04,820 --> 00:58:08,200 +that the way these +non-discrete gestures work, + +1296 +00:58:08,200 --> 00:58:13,200 +like drags and pinches, is that +while the gesture's active, + +1297 +00:58:14,450 --> 00:58:16,467 +we are going to modify some state, + +1298 +00:58:16,467 --> 00:58:19,930 +and that state is going to +affect the way things look + +1299 +00:58:19,930 --> 00:58:22,840 +while we're doing the pinch or the drag. + +1300 +00:58:22,840 --> 00:58:25,850 +And then, when the drag ends, +whatever the end state is, + +1301 +00:58:25,850 --> 00:58:29,790 +we are going to update +our steady state value + +1302 +00:58:29,790 --> 00:58:32,443 +for whatever, modifying our View. + +1303 +00:58:33,430 --> 00:58:35,510 +And it stays in that state. + +1304 +00:58:35,510 --> 00:58:39,090 +The key to understanding +how these gestures work, + +1305 +00:58:39,090 --> 00:58:40,940 +these non-discrete gestures is, + +1306 +00:58:40,940 --> 00:58:44,620 +that you're gonna have two +different pieces of state. + +1307 +00:58:44,620 --> 00:58:46,150 +So we're gonna have our state, + +1308 +00:58:46,150 --> 00:58:48,080 +which is our zoomScale normally, + +1309 +00:58:48,080 --> 00:58:52,517 +I'm gonna rename that +to steadyStateZoomScale. + +1310 +00:58:52,517 --> 00:58:54,900 +So this is gonna be the +zoomScale that we have + +1311 +00:58:54,900 --> 00:58:58,230 +just in steady state, not +while a gesture is going on. + +1312 +00:58:58,230 --> 00:59:00,980 +And then we're gonna have +a new piece of state, + +1313 +00:59:00,980 --> 00:59:03,020 +which is going to be @GestureState, + +1314 +00:59:03,020 --> 00:59:05,660 +which is different than +@State, slightly different, + +1315 +00:59:05,660 --> 00:59:08,844 +and it's going to be the gestureZoomScale. + +1316 +00:59:08,844 --> 00:59:11,128 +So this is going to be the +zoomScale we're going to use + +1317 +00:59:11,128 --> 00:59:13,490 +while the gesture is going on. + +1318 +00:59:13,490 --> 00:59:16,110 +Now, it's important to know +that this @GestureState + +1319 +00:59:16,110 --> 00:59:17,340 +could be of any type. + +1320 +00:59:17,340 --> 00:59:20,720 +It doesn't actually even have +to be the same kind of thing + +1321 +00:59:20,720 --> 00:59:22,590 +that your steady state one is doing. + +1322 +00:59:22,590 --> 00:59:26,190 +This just has to be whatever +information is going to change + +1323 +00:59:26,190 --> 00:59:29,680 +every time the pinch moves, +or a drag moves, or whatever, + +1324 +00:59:29,680 --> 00:59:32,100 +that let's you keep track of it. + +1325 +00:59:32,100 --> 00:59:34,010 +Now, in our case, when we're pinching, + +1326 +00:59:34,010 --> 00:59:37,920 +we do just wanna keep track +of whatever the scale is. + +1327 +00:59:37,920 --> 00:59:41,333 +So, that makes it so that our +zoomScale that we had before, + +1328 +00:59:41,333 --> 00:59:45,120 +we're still gonna have that, +and it's gonna be computed + +1329 +00:59:45,120 --> 00:59:46,340 +by just returning + +1330 +00:59:46,340 --> 00:59:51,340 +the steadyStateZoomScale +times the gestureZoomScale. + +1331 +00:59:53,290 --> 00:59:56,100 +Now this gestureZoomScale is 1.0, + +1332 +00:59:56,100 --> 00:59:57,940 +so when a gesture's not going on, + +1333 +00:59:57,940 --> 01:00:00,138 +it's just, this is gonna be equal right? + +1334 +01:00:00,138 --> 01:00:02,404 +steadyStateZoomScale times 1.0 + +1335 +01:00:02,404 --> 01:00:04,810 +is gonna be the same as +steadyStateZoomScale. + +1336 +01:00:04,810 --> 01:00:06,580 +But when our gesture's working, + +1337 +01:00:06,580 --> 01:00:08,820 +and a pinch moves out a little bit, + +1338 +01:00:08,820 --> 01:00:10,390 +it starts to be greater than one + +1339 +01:00:10,390 --> 01:00:12,170 +and our zoomScale's gonna go up. + +1340 +01:00:12,170 --> 01:00:15,950 +And when this pinch comes back +in, it's gonna go back lower. + +1341 +01:00:15,950 --> 01:00:20,550 +So our job is to make a +gesture, a pinching gesture, + +1342 +01:00:20,550 --> 01:00:23,260 +that modifies this gestureZoomScale + +1343 +01:00:23,260 --> 01:00:25,990 +only while we are pinching. + +1344 +01:00:25,990 --> 01:00:28,010 +And then, right at the end of the gesture, + +1345 +01:00:28,010 --> 01:00:31,290 +it's going to update this +to our steadyState value. + +1346 +01:00:31,290 --> 01:00:33,830 +And that's how we do gestures. + +1347 +01:00:33,830 --> 01:00:35,550 +Now, notice down here +we're getting an error, + +1348 +01:00:35,550 --> 01:00:37,720 +that's because the resuming to fit, + +1349 +01:00:37,720 --> 01:00:39,640 +we obviously are trying to zoomToFit + +1350 +01:00:39,640 --> 01:00:41,753 +our steadyStateZoomScale. + +1351 +01:00:43,690 --> 01:00:47,100 +We make a gesture for +pinching exactly the same way + +1352 +01:00:47,100 --> 01:00:49,699 +as we do this gesture for doubleTapToZoom. + +1353 +01:00:49,699 --> 01:00:51,810 +We're just gonna have .gesture, + +1354 +01:00:51,810 --> 01:00:53,420 +and we're gonna have a different function. + +1355 +01:00:53,420 --> 01:00:55,483 +I'm gonna call this my zoomGesture. + +1356 +01:00:56,407 --> 01:00:59,000 +And my zoomGesture actually +doesn't need the size, + +1357 +01:00:59,000 --> 01:01:01,810 +it's not like double tap +where it needs the size. + +1358 +01:01:01,810 --> 01:01:03,111 +So I have this zoomGesture. + +1359 +01:01:03,111 --> 01:01:04,890 +By the way, this could be a var, + +1360 +01:01:04,890 --> 01:01:06,080 +this doesn't have to be a func + +1361 +01:01:06,080 --> 01:01:08,090 +since it doesn't take any arguments. + +1362 +01:01:08,090 --> 01:01:10,780 +Let's go ahead and put +our zoomGesture down here. + +1363 +01:01:10,780 --> 01:01:15,333 +Let's put it right in here, +private func zoomGesture. + +1364 +01:01:17,339 --> 01:01:20,117 +And it's also gonna return some Gesture. + +1365 +01:01:21,660 --> 01:01:25,670 +Because we're passing it to +this gesture function here, + +1366 +01:01:25,670 --> 01:01:27,680 +it has to, some zoom Gesture. + +1367 +01:01:27,680 --> 01:01:30,080 +Also, by the way, I think +I'm gonna put my zoomGesture + +1368 +01:01:30,080 --> 01:01:31,420 +on the whole document. + +1369 +01:01:31,420 --> 01:01:34,560 +So I'm just gonna put this down +here on the whole document, + +1370 +01:01:34,560 --> 01:01:36,210 +not just on our background. + +1371 +01:01:36,210 --> 01:01:37,390 +I don't think there's a difference + +1372 +01:01:37,390 --> 01:01:40,970 +because our background, it +fills our entire document. + +1373 +01:01:40,970 --> 01:01:43,980 +But again, more just for code clarity, + +1374 +01:01:43,980 --> 01:01:47,150 +I'm going to separate these things out. + +1375 +01:01:47,150 --> 01:01:48,940 +This zoomGesture returns some Gesture. + +1376 +01:01:48,940 --> 01:01:49,910 +What kind of Gesture? + +1377 +01:01:49,910 --> 01:01:52,930 +It's gonna return what's +called a MagnificationGesture, + +1378 +01:01:52,930 --> 01:01:55,280 +that's how we do a pinch. + +1379 +01:01:55,280 --> 01:01:56,480 +So it's just gonna return it. + +1380 +01:01:56,480 --> 01:01:58,450 +And in fact, it's the +same as the double tap + +1381 +01:01:58,450 --> 01:02:00,810 +in that has an .onEnded. + +1382 +01:02:00,810 --> 01:02:01,750 +The only difference with the .onEnded + +1383 +01:02:01,750 --> 01:02:05,550 +of a MagnificationGesture +is that it gives you, + +1384 +01:02:05,550 --> 01:02:09,473 +as an argument, the finalGestureScale. + +1385 +01:02:10,570 --> 01:02:13,560 +So this is the gestureScale +that was at the end + +1386 +01:02:13,560 --> 01:02:16,680 +when the user's fingers +went up from the pinch. + +1387 +01:02:16,680 --> 01:02:18,320 +Now with this finalGestureScale, + +1388 +01:02:18,320 --> 01:02:23,320 +I can just reset my +steadyStateZoomScale to times equals + +1389 +01:02:24,100 --> 01:02:26,390 +my finalGestureScale. + +1390 +01:02:26,390 --> 01:02:28,700 +So if the gesture went to twice as big, + +1391 +01:02:28,700 --> 01:02:31,610 +and the fingers went up, +now in my steady state, + +1392 +01:02:31,610 --> 01:02:33,450 +I'm gonna be twice as big. + +1393 +01:02:33,450 --> 01:02:37,343 +And same thing if it +went down to half as big. + +1394 +01:02:37,343 --> 01:02:40,390 +So, the .onEnded, just +like the .onEnded down here + +1395 +01:02:40,390 --> 01:02:42,523 +with double tap was easy to implement. + +1396 +01:02:43,410 --> 01:02:45,350 +The trick, or the key parts + +1397 +01:02:45,350 --> 01:02:47,741 +of doing these non-discrete gestures, + +1398 +01:02:47,741 --> 01:02:49,732 +is while it's changing. + +1399 +01:02:49,732 --> 01:02:51,670 +So here's what that looks like. + +1400 +01:02:51,670 --> 01:02:53,448 +It's called .updating. + +1401 +01:02:53,448 --> 01:02:57,699 +And .updating takes an +argument which is your, + +1402 +01:02:57,699 --> 01:03:01,069 +whatever your @GestureState +is for this gesture. + +1403 +01:03:01,069 --> 01:03:03,870 +So, we'll say gestureZoomScale. + +1404 +01:03:05,000 --> 01:03:08,330 +However, you have to put +a dollar sign in front, + +1405 +01:03:08,330 --> 01:03:09,470 +and we're gonna talk about + +1406 +01:03:09,470 --> 01:03:11,500 +what this dollar sign means next week. + +1407 +01:03:11,500 --> 01:03:13,890 +It turns this into +what's called a Binding. + +1408 +01:03:13,890 --> 01:03:16,296 +So it is bound to this other var. + +1409 +01:03:16,296 --> 01:03:18,153 +But, you really don't need to know that + +1410 +01:03:18,153 --> 01:03:21,660 +to make this Gesture stuff at work. + +1411 +01:03:21,660 --> 01:03:24,010 +Understand it's just +essentially linking up + +1412 +01:03:24,010 --> 01:03:25,679 +to your @GestureState. + +1413 +01:03:25,679 --> 01:03:28,630 +And, of course, this +takes an argument as well, + +1414 +01:03:28,630 --> 01:03:29,550 +which is a function. + +1415 +01:03:29,550 --> 01:03:31,200 +This function is called + +1416 +01:03:31,200 --> 01:03:34,310 +every time the pinch gesture changes. + +1417 +01:03:34,310 --> 01:03:36,160 +So this is constantly being called, + +1418 +01:03:36,160 --> 01:03:38,020 +this little function is +constantly being called + +1419 +01:03:38,020 --> 01:03:40,490 +as the pinch moves in and out. + +1420 +01:03:40,490 --> 01:03:43,140 +And this thing has three arguments. + +1421 +01:03:43,140 --> 01:03:45,470 +The first one, very easy to understand, + +1422 +01:03:45,470 --> 01:03:47,667 +it's the latestGestureScale. + +1423 +01:03:49,169 --> 01:03:53,822 +That's just telling you what +the latest pinch looked like. + +1424 +01:03:53,822 --> 01:03:56,041 +The second argument is really weird. + +1425 +01:03:56,041 --> 01:04:00,260 +It's our @GestureState +as an inout parameter, + +1426 +01:04:00,260 --> 01:04:01,940 +we'll talk about that in a second. + +1427 +01:04:01,940 --> 01:04:05,482 +And the last argument +here is a transaction. + +1428 +01:04:05,482 --> 01:04:07,616 +I'm not gonna talk about transactions. + +1429 +01:04:07,616 --> 01:04:09,784 +Transactions are essentially capturing + +1430 +01:04:09,784 --> 01:04:13,470 +the animation environment +that this is all happening in. + +1431 +01:04:13,470 --> 01:04:17,550 +That's a little bit of +advanced use for animation + +1432 +01:04:17,550 --> 01:04:20,130 +that we're gonna pretty +much ignore in this class. + +1433 +01:04:20,130 --> 01:04:23,470 +So, we're gonna ignore +this argument as well. + +1434 +01:04:23,470 --> 01:04:26,480 +But we are gonna focus on +this ourGestureStateInOut. + +1435 +01:04:26,480 --> 01:04:29,150 +So, an inout parameter, +hopefully you got this from + +1436 +01:04:29,150 --> 01:04:31,289 +your reading assignment last week. + +1437 +01:04:31,289 --> 01:04:34,990 +But, it takes an argument in normally, + +1438 +01:04:34,990 --> 01:04:36,610 +so when something calls this function, + +1439 +01:04:36,610 --> 01:04:38,470 +the argument comes in normally. + +1440 +01:04:38,470 --> 01:04:43,118 +But then, if you actually +assign a value to this, + +1441 +01:04:43,118 --> 01:04:47,540 +then it gets copied +back out on the way out. + +1442 +01:04:47,540 --> 01:04:50,640 +So this gesture is +essentially passing you, + +1443 +01:04:50,640 --> 01:04:54,520 +your own @GestureState var in, + +1444 +01:04:54,520 --> 01:04:56,770 +letting you modify it in here. + +1445 +01:04:56,770 --> 01:04:58,190 +And then when you pass it out, + +1446 +01:04:58,190 --> 01:05:00,870 +it turns it up here and changes it. + +1447 +01:05:00,870 --> 01:05:02,690 +So why is that happening? + +1448 +01:05:02,690 --> 01:05:06,650 +Why are we not just changing +our gestureZoomScale + +1449 +01:05:06,650 --> 01:05:07,510 +directly in here, + +1450 +01:05:07,510 --> 01:05:10,380 +why am I not saying +gestureZoomScale equals something? + +1451 +01:05:10,380 --> 01:05:13,070 +Why do I do it through this variable? + +1452 +01:05:13,070 --> 01:05:15,930 +Well the answer for that is +that this @GestureState var, + +1453 +01:05:15,930 --> 01:05:20,380 +while it's in your View, is +really owned by this Gesture. + +1454 +01:05:20,380 --> 01:05:22,570 +Other than the initial +value that you give it, + +1455 +01:05:22,570 --> 01:05:25,590 +you should never assign +a value to this directly. + +1456 +01:05:25,590 --> 01:05:28,370 +Always let the Gesture handle it. + +1457 +01:05:28,370 --> 01:05:30,540 +What does the Gesture +do with it, by the way? + +1458 +01:05:30,540 --> 01:05:32,500 +Well, when the Gesture is not happening, + +1459 +01:05:32,500 --> 01:05:34,190 +it leaves it at 1.0. + +1460 +01:05:34,190 --> 01:05:36,110 +And then while the Gesture is happening, + +1461 +01:05:36,110 --> 01:05:39,100 +it's passing it to you and +you can modify it here. + +1462 +01:05:39,100 --> 01:05:42,060 +And then when it's over, +it goes back to 1.0. + +1463 +01:05:42,060 --> 01:05:45,770 +So, the Gesture wants to own that var, + +1464 +01:05:45,770 --> 01:05:47,620 +and so you are not allowed to own it. + +1465 +01:05:47,620 --> 01:05:49,190 +This inout business, + +1466 +01:05:49,190 --> 01:05:50,640 +if you don't really +understand what I'm saying + +1467 +01:05:50,640 --> 01:05:52,980 +about inout parameters, +didn't understand the reading, + +1468 +01:05:52,980 --> 01:05:54,580 +maybe go back and do the reading. + +1469 +01:05:54,580 --> 01:05:56,560 +But even then if you don't understand it, + +1470 +01:05:56,560 --> 01:05:59,790 +then just understand +that the Gesture here, + +1471 +01:05:59,790 --> 01:06:00,890 +this MagnificationGesture + +1472 +01:06:00,890 --> 01:06:04,420 +only wants you to modify +your @GestureState + +1473 +01:06:04,420 --> 01:06:07,140 +inside this function +that's called repeatedly + +1474 +01:06:07,140 --> 01:06:09,060 +as the pinch happens. + +1475 +01:06:09,060 --> 01:06:11,920 +Now, because that's what this is doing, + +1476 +01:06:11,920 --> 01:06:16,372 +a lot of people will rename +this to be the exact same name + +1477 +01:06:16,372 --> 01:06:20,301 +as their @GestureState variable. + +1478 +01:06:20,301 --> 01:06:23,732 +And when they do this, call +it the exact same thing, + +1479 +01:06:23,732 --> 01:06:27,183 +now it kinda looks like you +are changing this in here. + +1480 +01:06:28,160 --> 01:06:29,360 +I'm actually a fan of that, + +1481 +01:06:29,360 --> 01:06:31,320 +I don't say this at the beginning, + +1482 +01:06:31,320 --> 01:06:34,040 +because I want you to understand +what's happening here. + +1483 +01:06:34,040 --> 01:06:37,853 +But, I think naming this +the same is a good idea. + +1484 +01:06:38,980 --> 01:06:40,200 +So, what do we wanna do + +1485 +01:06:40,200 --> 01:06:42,500 +every time that pinch goes in and out + +1486 +01:06:42,500 --> 01:06:44,332 +or changes a little bit? + +1487 +01:06:44,332 --> 01:06:47,727 +Well, here we just want to +grab the latestGestureScale. + +1488 +01:06:47,727 --> 01:06:51,766 +So whatever this is, the +last time the pinch moved, + +1489 +01:06:51,766 --> 01:06:54,528 +we want to set that as +our gestureZoomScale. + +1490 +01:06:54,528 --> 01:06:59,360 +So this is the simplest possible +thing to do while updating. + +1491 +01:06:59,360 --> 01:07:00,780 +We're gonna do a little +more complicated thing + +1492 +01:07:00,780 --> 01:07:04,333 +when we do the DragGesture +and panning the thing around. + +1493 +01:07:04,333 --> 01:07:08,870 +So that's all that's required +to support this zoom gesture. + +1494 +01:07:08,870 --> 01:07:11,700 +We created a zoom gesture, +a MagnificationGesture, + +1495 +01:07:11,700 --> 01:07:14,230 +it updates our steady state when it ends. + +1496 +01:07:14,230 --> 01:07:17,052 +While it's going on, it +updates this @GestureState, + +1497 +01:07:17,052 --> 01:07:18,689 +which is transient, we only do it + +1498 +01:07:18,689 --> 01:07:19,973 +while the gesture is happening. + +1499 +01:07:19,973 --> 01:07:23,984 +And all we do is attach this +zoom gesture to our ZStack, + +1500 +01:07:23,984 --> 01:07:27,151 +so that when that gesture +happens in our ZStack, + +1501 +01:07:27,151 --> 01:07:29,520 +we recognize it. + +1502 +01:07:29,520 --> 01:07:31,720 +All right, so here's our little document. + +1503 +01:07:31,720 --> 01:07:34,257 +Hold down option to get two fingers, + +1504 +01:07:34,257 --> 01:07:37,493 +and we can zoom in and zoom out. + +1505 +01:07:38,414 --> 01:07:41,970 +And we can still double tap +to show the whole image. + +1506 +01:07:41,970 --> 01:07:46,083 +We could also go over here +and get our huge background. + +1507 +01:07:46,970 --> 01:07:50,887 +And we can zoom in and out, double tap. + +1508 +01:07:53,210 --> 01:07:55,890 +We can do the same thing +for panning around, + +1509 +01:07:55,890 --> 01:07:57,570 +'cause if I'm zoomed way in here + +1510 +01:07:57,570 --> 01:07:59,110 +and I wanna see this other horse, + +1511 +01:07:59,110 --> 01:08:02,490 +I'd like to be able to drag this over. + +1512 +01:08:02,490 --> 01:08:05,540 +For pan, I'm not gonna +go through all the detail + +1513 +01:08:05,540 --> 01:08:07,770 +of the code again, typing this all in, + +1514 +01:08:07,770 --> 01:08:12,110 +because it's very similar +to doing the same thing + +1515 +01:08:12,110 --> 01:08:14,040 +we did here with the zoom gesture, + +1516 +01:08:14,040 --> 01:08:17,812 +but I am gonna walk +through the code with you. + +1517 +01:08:17,812 --> 01:08:21,620 +And for the pan, this is +the code that I just added. + +1518 +01:08:21,620 --> 01:08:24,490 +We are going to still +have steadyStatePanOffset, + +1519 +01:08:24,490 --> 01:08:26,590 +and still gonna have the gesturePanOffset, + +1520 +01:08:26,590 --> 01:08:29,310 +which is gonna be only the +pan while we're dragging, + +1521 +01:08:29,310 --> 01:08:31,070 +and then that'll make a pan offset + +1522 +01:08:31,070 --> 01:08:33,350 +by adding the two together + +1523 +01:08:33,350 --> 01:08:35,860 +and multiplying by zoomScale, of course. + +1524 +01:08:35,860 --> 01:08:37,770 +By the way, I am doing some things here + +1525 +01:08:37,770 --> 01:08:39,330 +like adding points together, + +1526 +01:08:39,330 --> 01:08:41,079 +normally you can't do that in Swift, + +1527 +01:08:41,079 --> 01:08:44,600 +but I added some EmojiArt +extensions down here + +1528 +01:08:44,600 --> 01:08:48,070 +for point and size, to be +able to make this code here + +1529 +01:08:48,070 --> 01:08:49,260 +look a lot simpler. + +1530 +01:08:49,260 --> 01:08:51,940 +So you can check those +out if you want as well. + +1531 +01:08:51,940 --> 01:08:53,327 +This feels exactly the same, right, + +1532 +01:08:53,327 --> 01:08:54,480 +panOffset feels like zoomScale. + +1533 +01:08:54,480 --> 01:08:58,541 +It's just taking the steady +state and adding the gesture's + +1534 +01:08:58,541 --> 01:09:01,990 +while-in-motion value. + +1535 +01:09:01,990 --> 01:09:04,260 +So let's look at panGesture, +looking slightly different + +1536 +01:09:04,260 --> 01:09:05,870 +than a MagnificationGesture. + +1537 +01:09:05,870 --> 01:09:07,010 +It's a DragGesture. + +1538 +01:09:07,010 --> 01:09:09,480 +And on the ended, it's +pretty much the same, + +1539 +01:09:09,480 --> 01:09:12,300 +we get our final drag value. + +1540 +01:09:12,300 --> 01:09:13,950 +The only thing about this is that + +1541 +01:09:13,950 --> 01:09:16,790 +the drag value that's passed to us + +1542 +01:09:16,790 --> 01:09:21,370 +is a little more complicated +than it is for a magnification. + +1543 +01:09:21,370 --> 01:09:23,730 +For magnification it's +just a simple scale, + +1544 +01:09:23,730 --> 01:09:27,130 +that is the value that's passed, +both while we're updating + +1545 +01:09:27,130 --> 01:09:28,600 +and when it ends. + +1546 +01:09:28,600 --> 01:09:30,500 +But a drag has more information. + +1547 +01:09:30,500 --> 01:09:32,930 +So we're gonna go and +actually take a look at this + +1548 +01:09:32,930 --> 01:09:34,980 +in the documentation. + +1549 +01:09:34,980 --> 01:09:36,490 +Open it up. + +1550 +01:09:36,490 --> 01:09:38,230 +Here's DragGesture. + +1551 +01:09:38,230 --> 01:09:40,843 +And it's explaining a +little bit this up here. + +1552 +01:09:40,843 --> 01:09:42,970 +But down in here you can see, + +1553 +01:09:42,970 --> 01:09:45,269 +when we have the .updating and .onEnded, + +1554 +01:09:45,269 --> 01:09:47,690 +this value that's being passed to us, + +1555 +01:09:47,690 --> 01:09:50,760 +when we're handling things +happening in the gesture, + +1556 +01:09:50,760 --> 01:09:54,630 +is actually a type +DragGesture.Value right here. + +1557 +01:09:54,630 --> 01:09:56,850 +So I'm gonna click on this .Value + +1558 +01:09:56,850 --> 01:09:58,730 +and we're gonna see what it looks like. + +1559 +01:09:58,730 --> 01:10:01,350 +You can see that this +value is not a simple Float + +1560 +01:10:01,350 --> 01:10:03,850 +like the scale was in +MagnificationGesture. + +1561 +01:10:03,850 --> 01:10:06,888 +It's actually a struct +and it has the location + +1562 +01:10:06,888 --> 01:10:11,240 +of where you are +currently with the finger, + +1563 +01:10:11,240 --> 01:10:14,080 +and also the start location, +where you started from. + +1564 +01:10:14,080 --> 01:10:15,626 +Even the time. + +1565 +01:10:15,626 --> 01:10:18,870 +So it's time stamped every +single time it updates, + +1566 +01:10:18,870 --> 01:10:21,740 +so you can know how fast it's +moving and things like that. + +1567 +01:10:21,740 --> 01:10:25,080 +And here's the translation, +which is a CGSize, + +1568 +01:10:25,080 --> 01:10:28,050 +width and height, how far +it's gone since the start + +1569 +01:10:28,050 --> 01:10:28,883 +of the pan. + +1570 +01:10:28,883 --> 01:10:33,487 +And we're gonna use this +translation to update our offset. + +1571 +01:10:34,362 --> 01:10:37,889 +So here it is right here, +we're gonna say translation, + +1572 +01:10:37,889 --> 01:10:40,361 +just drag value translation in here. + +1573 +01:10:40,361 --> 01:10:42,390 +And all we're gonna do +is take the translation, + +1574 +01:10:42,390 --> 01:10:45,060 +we have to divide it by +the zoomScale, of course, + +1575 +01:10:45,060 --> 01:10:49,040 +and we're gonna add it, in +the end, to our steady state, + +1576 +01:10:49,040 --> 01:10:50,550 +and while it's updating, + +1577 +01:10:50,550 --> 01:10:52,960 +it's going to be our gesture pan state. + +1578 +01:10:52,960 --> 01:10:55,100 +And then we just add those two together. + +1579 +01:10:55,100 --> 01:10:55,933 +And off we go. + +1580 +01:10:55,933 --> 01:10:58,040 +Otherwise it's very, very similar. + +1581 +01:10:58,040 --> 01:10:59,710 +So now that we have this PanOffset, + +1582 +01:10:59,710 --> 01:11:02,030 +we just need to use it everywhere + +1583 +01:11:02,030 --> 01:11:04,710 +that it makes sense to have a pan. + +1584 +01:11:04,710 --> 01:11:06,440 +So that's easy, it's a +lot of the same places + +1585 +01:11:06,440 --> 01:11:07,780 +we did the zoomScale. + +1586 +01:11:07,780 --> 01:11:10,570 +Right here where we do the +scaleEffect, of course, + +1587 +01:11:10,570 --> 01:11:12,720 +we want to offset our View. + +1588 +01:11:12,720 --> 01:11:14,995 +Everyone remembers the offset, + +1589 +01:11:14,995 --> 01:11:18,390 +you probably used that a lot in homework 3 + +1590 +01:11:18,390 --> 01:11:19,570 +or maybe through animation, + +1591 +01:11:19,570 --> 01:11:23,490 +but here's the offset +for the background image. + +1592 +01:11:23,490 --> 01:11:25,040 +How about the offset for the emoji? + +1593 +01:11:25,040 --> 01:11:27,071 +So that's here in this position thing. + +1594 +01:11:27,071 --> 01:11:29,050 +And, position remember, + +1595 +01:11:29,050 --> 01:11:31,690 +is doing the coordinate +system transformation + +1596 +01:11:31,690 --> 01:11:34,360 +from (0, 0) in the center and so is drop. + +1597 +01:11:34,360 --> 01:11:37,210 +So both of these are going +to need to be adjusted, + +1598 +01:11:37,210 --> 01:11:38,540 +both position and this. + +1599 +01:11:38,540 --> 01:11:40,880 +Let's do this one first while we're here. + +1600 +01:11:40,880 --> 01:11:43,080 +Just gonna throw this right in here, + +1601 +01:11:43,080 --> 01:11:47,810 +location equals a CGPoint, +that is the x-location, + +1602 +01:11:47,810 --> 01:11:52,810 +but minus the panOffset's width, + +1603 +01:11:53,550 --> 01:11:58,550 +and the y is the location.y +minus the panOffset's height. + +1604 +01:12:00,970 --> 01:12:03,080 +And then that position right here, + +1605 +01:12:03,080 --> 01:12:04,554 +let's go down to fix that. + +1606 +01:12:04,554 --> 01:12:06,380 +It's doing the same transition + +1607 +01:12:06,380 --> 01:12:08,740 +in the opposite direction actually. + +1608 +01:12:08,740 --> 01:12:10,620 +It's right here. + +1609 +01:12:10,620 --> 01:12:15,620 +We'll say location equals +a CGPoint which equals x. + +1610 +01:12:16,037 --> 01:12:19,640 +x plus the panOffset.width, + +1611 +01:12:19,640 --> 01:12:24,360 +and the y is the location.y +plus the panOffset.height. + +1612 +01:12:26,090 --> 01:12:30,660 +Plus that, and the only +other thing I wanna do with + +1613 +01:12:30,660 --> 01:12:33,470 +panOffset is when I double +click the zoomToFit, + +1614 +01:12:33,470 --> 01:12:36,390 +we wanna, I think, reset it to the center. + +1615 +01:12:36,390 --> 01:12:41,390 +So let's say steady, our +steadyStatePanOffset equals .zero, + +1616 +01:12:42,800 --> 01:12:46,080 +which is the same as +CGSize.zero, by the way. + +1617 +01:12:46,080 --> 01:12:49,970 +But, Swift can infer the CGSize for us. + +1618 +01:12:49,970 --> 01:12:51,870 +And I think that's all we need to do. + +1619 +01:12:51,870 --> 01:12:54,450 +Those are the only places +that the pan matters. + +1620 +01:12:54,450 --> 01:12:56,010 +Just moving the background around, + +1621 +01:12:56,010 --> 01:12:56,843 +and then making sure + +1622 +01:12:56,843 --> 01:12:59,560 +we're doing the right +coordinate system transfer + +1623 +01:12:59,560 --> 01:13:01,580 +on the positions of the emojis. + +1624 +01:13:01,580 --> 01:13:04,840 +And just like we added the +gesture for a zoomGesture, + +1625 +01:13:04,840 --> 01:13:08,983 +let's add the gesture for our panGesture. + +1626 +01:13:10,777 --> 01:13:13,719 +And you can add multiple gestures here. + +1627 +01:13:13,719 --> 01:13:17,250 +If they might conflict with +each other in some ways, + +1628 +01:13:17,250 --> 01:13:20,997 +then there are methods that +you can find in Gesture + +1629 +01:13:20,997 --> 01:13:24,750 +for doing Gestures simultaneously, +or even exclusively, + +1630 +01:13:24,750 --> 01:13:27,410 +where one Gesture, once it wins, + +1631 +01:13:27,410 --> 01:13:28,440 +will not allow the other one. + +1632 +01:13:28,440 --> 01:13:31,963 +You can take a look at that +in the Gesture documentation. + +1633 +01:13:35,330 --> 01:13:36,910 +All right, let's see. + +1634 +01:13:36,910 --> 01:13:38,370 +Woo, there we go. + +1635 +01:13:38,370 --> 01:13:42,460 +We can do that, we can +zoom way in, look around, + +1636 +01:13:42,460 --> 01:13:43,947 +and zoom out. + +1637 +01:13:45,570 --> 01:13:48,714 +So we're now, nice combination +of zooming and panning + +1638 +01:13:48,714 --> 01:13:50,683 +throughout our whole document. + +1639 +01:13:51,550 --> 01:13:54,780 +Now, you're homework +assignment is going to be + +1640 +01:13:54,780 --> 01:13:57,146 +to do the same thing, zooming and panning, + +1641 +01:13:57,146 --> 01:14:00,150 +but with these little emoji. + +1642 +01:14:00,150 --> 01:14:03,360 +In that case is, moving the emojis around, + +1643 +01:14:03,360 --> 01:14:06,870 +and also resizing the emojis +so that they're larger + +1644 +01:14:06,870 --> 01:14:08,830 +compared to the background. + +1645 +01:14:08,830 --> 01:14:12,790 +And that's really gonna let us +build real beautiful EmojiArt + +1646 +01:14:12,790 --> 01:14:15,340 +because we can actually control the sizing + +1647 +01:14:15,340 --> 01:14:16,580 +and positioning of things. + +1648 +01:14:16,580 --> 01:14:18,680 +So you're gonna have +to manage the selection + +1649 +01:14:18,680 --> 01:14:20,740 +of these things, selecting them. + +1650 +01:14:20,740 --> 01:14:21,925 +That homework, by the way, is next week. + +1651 +01:14:21,925 --> 01:14:24,610 +In your assignment A3, you don't have to, + +1652 +01:14:24,610 --> 01:14:27,010 +you're not using any Gestures +in your assignment A3, + +1653 +01:14:27,010 --> 01:14:28,920 +this is next week's +homework I'm talking about. + +1654 +01:14:28,920 --> 01:14:30,420 +And as I mentioned earlier, + +1655 +01:14:30,420 --> 01:14:32,290 +that one data structure +you might wanna use + +1656 +01:14:32,290 --> 01:14:34,915 +to keep your selection, is a Set. + +1657 +01:14:34,915 --> 01:14:39,620 +So, if you're gonna put your +little Emojis into a Set, + +1658 +01:14:39,620 --> 01:14:41,370 +they need to be Hashable. + +1659 +01:14:41,370 --> 01:14:43,200 +So let's talk about how that works. + +1660 +01:14:43,200 --> 01:14:47,034 +Back here in EmojiArt we +have our Emojis, right here. + +1661 +01:14:47,034 --> 01:14:49,740 +And, they're Identifiable, +and they're Codable, + +1662 +01:14:49,740 --> 01:14:51,833 +and you can also make them Hashable. + +1663 +01:14:52,810 --> 01:14:54,440 +And, if you mark it Hashable, + +1664 +01:14:54,440 --> 01:14:56,180 +it means they can be put in a Set. + +1665 +01:14:56,180 --> 01:14:59,710 +Note that you don't have to +do anything, it just works. + +1666 +01:14:59,710 --> 01:15:01,630 +And that's because, again, + +1667 +01:15:01,630 --> 01:15:04,200 +the types in this struct +are such that Swift + +1668 +01:15:04,200 --> 01:15:06,970 +can automatically do +this hashability for you. + +1669 +01:15:06,970 --> 01:15:08,861 +So not only could you put this in a Set, + +1670 +01:15:08,861 --> 01:15:12,200 +but Emojis could also be if +the key is in a Dictionary + +1671 +01:15:12,200 --> 01:15:13,033 +if you wanted. + +1672 +01:15:13,033 --> 01:15:14,916 +I don't think you're gonna +need that for your homework. + +1673 +01:15:14,916 --> 01:15:17,990 +But, I just wanted to +show you that real quick + +1674 +01:15:17,990 --> 01:15:20,400 +in case you wanted to do that. + +1675 +01:15:20,400 --> 01:15:22,431 +So that's it for today. + +1676 +01:15:22,431 --> 01:15:26,400 +We added a lot of cool +features to our EmojiArt. + +1677 +01:15:26,400 --> 01:15:31,400 +And we can save it, and +when we leave and come back, + +1678 +01:15:33,200 --> 01:15:36,070 +we don't lose all that +wonderful work that we did. + +1679 +01:15:36,070 --> 01:15:38,300 +And of course we have double tap, + +1680 +01:15:38,300 --> 01:15:40,533 +and we can resize and pan. + +1681 +01:15:42,290 --> 01:15:43,830 +So there's a lot more things we can do + +1682 +01:15:43,830 --> 01:15:45,740 +to make our EmojiArt even better, + +1683 +01:15:45,740 --> 01:15:48,323 +and we'll dive into all of that next week. + +1684 +01:15:49,670 --> 01:15:53,133 +- For more, please visit +us at standford.edu. diff --git a/subtitles/en/Lecture 9. Data Flow b/subtitles/en/Lecture 9. Data Flow new file mode 100644 index 0000000..1f1b1d2 --- /dev/null +++ b/subtitles/en/Lecture 9. Data Flow @@ -0,0 +1,7040 @@ +1 +00:00:00,182 --> 00:00:02,932 +(ethereal music) + +2 +00:00:04,920 --> 00:00:06,520 +- [Narrator] Stanford University + +3 +00:00:08,720 --> 00:00:10,820 +- [Instructor] We are back, lecture nine, + +4 +00:00:10,820 --> 00:00:15,820 +Stanford CS193p, Spring of 2020. + +5 +00:00:16,320 --> 00:00:19,580 +Today we are going to talk +about a super important topic, + +6 +00:00:19,580 --> 00:00:21,110 +property wrappers. + +7 +00:00:21,110 --> 00:00:24,816 +We're finally gonna understand +what things like @State + +8 +00:00:24,816 --> 00:00:29,220 +and @Published are really +doing under the covers. + +9 +00:00:29,220 --> 00:00:30,620 +Then we're gonna talk about Publishers + +10 +00:00:30,620 --> 00:00:33,060 +because, when we start +talking about @Published + +11 +00:00:33,060 --> 00:00:35,740 +it's gonna rapidly lead +to this other topic, + +12 +00:00:35,740 --> 00:00:38,270 +also another very important topic, + +13 +00:00:38,270 --> 00:00:40,530 +however, I only have a little bit of time + +14 +00:00:40,530 --> 00:00:41,900 +to talk about it today, + +15 +00:00:41,900 --> 00:00:44,640 +we will talk about it much +more later in the quarter, + +16 +00:00:44,640 --> 00:00:47,410 +just gonna get the overview today. + +17 +00:00:47,410 --> 00:00:49,870 +Then we'll dive into a +demo where I'll show you + +18 +00:00:49,870 --> 00:00:51,670 +a lot of stuff about Publishers + +19 +00:00:51,670 --> 00:00:54,390 +and also talk about @Binding + +20 +00:00:54,390 --> 00:00:56,970 +which is a new property wrapper +you're gonna learn about + +21 +00:00:56,970 --> 00:00:58,003 +in these slides. + +22 +00:00:59,070 --> 00:01:01,110 +So let's talk about property wrappers. + +23 +00:01:01,110 --> 00:01:03,679 +These are there @Somethings +that you're seeing, + +24 +00:01:03,679 --> 00:01:06,200 +@State, @Publisher. + +25 +00:01:06,200 --> 00:01:09,180 +Turns out this thing is actually a struct + +26 +00:01:09,180 --> 00:01:11,580 +and that's struct has code in it + +27 +00:01:11,580 --> 00:01:14,150 +that applies some kind +of template behavior + +28 +00:01:14,150 --> 00:01:17,630 +to all the vars that they wrap. + +29 +00:01:17,630 --> 00:01:19,080 +We already know about +some of these behaviors, + +30 +00:01:19,080 --> 00:01:22,310 +like @State, it makes +a var live in the heap, + +31 +00:01:22,310 --> 00:01:24,040 +right, makes it writable in a View + +32 +00:01:24,040 --> 00:01:26,870 +that would otherwise be unwritable. + +33 +00:01:26,870 --> 00:01:30,580 +We know that @Published +publishes the changes of a var + +34 +00:01:30,580 --> 00:01:32,980 +causing Views to redraw +and things like that. + +35 +00:01:32,980 --> 00:01:36,170 +Same thing with @ObservedObject, +watching our ViewModel + +36 +00:01:36,170 --> 00:01:39,510 +when it changes it makes our View redraw. + +37 +00:01:39,510 --> 00:01:42,090 +Property wrapper is a +feature in the Swift language + +38 +00:01:42,090 --> 00:01:45,890 +that adds some syntactic +sugar to make these structs + +39 +00:01:45,890 --> 00:01:48,490 +really easy to use in your code. + +40 +00:01:48,490 --> 00:01:51,210 +So let's talk about that syntactic sugar + +41 +00:01:51,210 --> 00:01:53,429 +and to do that we're +gonna use this example, + +42 +00:01:53,429 --> 00:01:57,280 +@Published var emoji, of type EmojiArt + +43 +00:01:57,280 --> 00:02:01,433 +equals EmojiArt(), we have +this in our EmojiArt demo. + +44 +00:02:02,410 --> 00:02:04,410 +What's really happening here? + +45 +00:02:04,410 --> 00:02:06,200 +Well, as I said, this line of code + +46 +00:02:06,200 --> 00:02:11,120 +is really creating a struct +and what type is that struct? + +47 +00:02:11,120 --> 00:02:14,220 +It's of type Published. + +48 +00:02:14,220 --> 00:02:17,600 +That is the type of this struct. + +49 +00:02:17,600 --> 00:02:21,030 +And inside this struct there +is a very important var + +50 +00:02:21,030 --> 00:02:22,717 +called its wrappedValue. + +51 +00:02:23,650 --> 00:02:26,640 +Now the type of this wrappedValue var + +52 +00:02:26,640 --> 00:02:29,380 +for most property wrappers + +53 +00:02:29,380 --> 00:02:32,350 +is the type of the var it's +wrapping, that emojiArt thing, + +54 +00:02:32,350 --> 00:02:34,040 +so that's of type EmojiArt. + +55 +00:02:34,040 --> 00:02:36,540 +That's awesome, it's got the +little wrappedValue in there + +56 +00:02:36,540 --> 00:02:39,020 +which is an EmojiArt. + +57 +00:02:39,020 --> 00:02:42,070 +Swift, when you do this @Published, + +58 +00:02:42,070 --> 00:02:44,140 +it builds one of these structs + +59 +00:02:44,140 --> 00:02:46,990 +and makes a couple of +vars available to you. + +60 +00:02:46,990 --> 00:02:49,850 +The first one is _emojiArt. + +61 +00:02:49,850 --> 00:02:53,090 +Now we have not seen this +one but it's in there. + +62 +00:02:53,090 --> 00:02:58,090 +_emojiArt is of type Published, +it's basically of the type + +63 +00:02:58,370 --> 00:03:01,790 +of this struct that +we're talking about here. + +64 +00:03:01,790 --> 00:03:06,070 +And it gets initialized by +creating a Published struct + +65 +00:03:06,070 --> 00:03:09,540 +and setting that wrappedValue +to whatever you initialized + +66 +00:03:09,540 --> 00:03:11,360 +the var that you're wrapping. + +67 +00:03:11,360 --> 00:03:12,650 +All right, emojiArt, up there, + +68 +00:03:12,650 --> 00:03:15,370 +we initialize it to an empty EmojiArt, + +69 +00:03:15,370 --> 00:03:18,150 +so our Published struct gets initialized + +70 +00:03:18,150 --> 00:03:20,350 +with that wrappedValue there. + +71 +00:03:20,350 --> 00:03:22,170 +That makes a lot of sense. + +72 +00:03:22,170 --> 00:03:24,340 +Now we don't actually access this purple + +73 +00:03:24,340 --> 00:03:28,027 +_emojiArt very often, however it's there + +74 +00:03:28,027 --> 00:03:30,960 +and we do access this next var + +75 +00:03:30,960 --> 00:03:33,020 +which looks just like +the thing we're wrapping, + +76 +00:03:33,020 --> 00:03:36,130 +it's flashing up there, var emojiArt, + +77 +00:03:36,130 --> 00:03:40,200 +but that turns out to +be a computed property. + +78 +00:03:40,200 --> 00:03:44,020 +And conceptually it's +getting the wrappedValue + +79 +00:03:44,020 --> 00:03:46,370 +out of the _emojiArt and it's setting + +80 +00:03:46,370 --> 00:03:49,690 +by setting the _emojiArt's wrappedValue. + +81 +00:03:49,690 --> 00:03:52,450 +So that's really what's +going on here, conceptually. + +82 +00:03:52,450 --> 00:03:53,900 +Now there's more to it than that. + +83 +00:03:53,900 --> 00:03:55,940 +Of course this Published is just a struct + +84 +00:03:55,940 --> 00:03:58,020 +and we can do a lot of different +things with wrappedValue + +85 +00:03:58,020 --> 00:04:01,570 +but this is basically what's going on. + +86 +00:04:01,570 --> 00:04:03,140 +But wait, there's more. + +87 +00:04:03,140 --> 00:04:05,870 +There's yet another var in that struct + +88 +00:04:05,870 --> 00:04:07,927 +called the projectedValue. + +89 +00:04:09,660 --> 00:04:11,650 +You access this projectedValue + +90 +00:04:11,650 --> 00:04:14,693 +with yet another syntactic +sugar var, $emojiArt. + +91 +00:04:15,600 --> 00:04:18,060 +So we have _emojiArt, that's the struct, + +92 +00:04:18,060 --> 00:04:20,500 +we have nothing in front of it emojiArt, + +93 +00:04:20,500 --> 00:04:24,470 +that's getting the wrappedValue +via computed property, + +94 +00:04:24,470 --> 00:04:26,210 +then you have $emojiArt + +95 +00:04:26,210 --> 00:04:28,283 +which is accessing this projectedValue. + +96 +00:04:29,340 --> 00:04:31,760 +Well what is this projectedValue? + +97 +00:04:31,760 --> 00:04:34,200 +Well that's totally up +to the property wrapper. + +98 +00:04:34,200 --> 00:04:37,510 +So each property wrapper has +a different projectedValue + +99 +00:04:37,510 --> 00:04:39,500 +that is totally its decision. + +100 +00:04:39,500 --> 00:04:42,490 +For example, @Published, that struct, + +101 +00:04:42,490 --> 00:04:45,960 +it chooses to have its +projectedValue be a Publisher + +102 +00:04:45,960 --> 00:04:49,593 +that publishes the +wrappedValue and never fails. + +103 +00:04:50,450 --> 00:04:54,330 +That's what this type +Publisher<EmojiArt, Never> means, + +104 +00:04:54,330 --> 00:04:58,970 +it means a Publisher that is +periodically emitting a value + +105 +00:04:58,970 --> 00:05:01,740 +which is an emojiArt and never fails. + +106 +00:05:01,740 --> 00:05:04,220 +Now, of course, the value that +it is periodically emitting + +107 +00:05:04,220 --> 00:05:07,350 +is any time that wrappedValue, +that emojiArt, changes + +108 +00:05:07,350 --> 00:05:09,380 +it publishes that change. + +109 +00:05:09,380 --> 00:05:10,960 +And we're gonna talk +about Publishers later + +110 +00:05:10,960 --> 00:05:12,510 +and this'll make more sense to you, + +111 +00:05:12,510 --> 00:05:14,810 +but that is the projectedValue + +112 +00:05:14,810 --> 00:05:18,350 +of an @Published property wrapper. + +113 +00:05:18,350 --> 00:05:20,400 +And each one is gonna +have a different type + +114 +00:05:20,400 --> 00:05:21,900 +so we're gonna have to go through + +115 +00:05:21,900 --> 00:05:25,403 +and talk about each of those +on a case by case basis. + +116 +00:05:26,280 --> 00:05:27,910 +But first let's talk about why we do + +117 +00:05:27,910 --> 00:05:29,430 +this property wrapper thing. + +118 +00:05:29,430 --> 00:05:30,773 +What's the point of it? + +119 +00:05:30,773 --> 00:05:33,990 +Well the main point is +that the wrapper struct, + +120 +00:05:33,990 --> 00:05:36,360 +like Published, can do something + +121 +00:05:36,360 --> 00:05:39,283 +when the wrappedValue is got or set. + +122 +00:05:40,170 --> 00:05:41,900 +It can get involved. + +123 +00:05:41,900 --> 00:05:44,520 +For example, @Published, what does it do + +124 +00:05:44,520 --> 00:05:46,340 +when its wrappedValue is set? + +125 +00:05:46,340 --> 00:05:48,300 +Well, it publishes it, + +126 +00:05:48,300 --> 00:05:51,060 +through it's little $emojiArt Publisher. + +127 +00:05:51,060 --> 00:05:55,730 +Not only that, but @Published +causes objectWillChange.send + +128 +00:05:55,730 --> 00:05:58,960 +to happen in the ObservableObject it's in. + +129 +00:05:58,960 --> 00:06:02,160 +So, it's getting involved +in the setting and getting + +130 +00:06:02,160 --> 00:06:05,743 +of that var and that's what +property wrappers really do. + +131 +00:06:06,950 --> 00:06:09,870 +So let's look at the +actions that are taken + +132 +00:06:09,870 --> 00:06:13,190 +and the projectedValue of +each of the property wrappers + +133 +00:06:13,190 --> 00:06:14,023 +that we know. + +134 +00:06:15,927 --> 00:06:19,920 +@State, we've seen that one +multiple times in our View. + +135 +00:06:19,920 --> 00:06:24,750 +The wrappedValue of an +@State is anything, really, + +136 +00:06:24,750 --> 00:06:27,840 +any var, probably gonna be a value type. + +137 +00:06:27,840 --> 00:06:30,940 +What it does, it stores the wrappedValue + +138 +00:06:30,940 --> 00:06:32,520 +in the heap. + +139 +00:06:32,520 --> 00:06:34,060 +And that's so that it can be changeable + +140 +00:06:34,060 --> 00:06:35,550 +'cause normally our Views are read only, + +141 +00:06:35,550 --> 00:06:36,990 +we can't change 'em, but +if it lives in the heap + +142 +00:06:36,990 --> 00:06:38,710 +we can change it over there. + +143 +00:06:38,710 --> 00:06:40,370 +It also invalidates the View + +144 +00:06:40,370 --> 00:06:43,090 +whenever that wrappedValue changes. + +145 +00:06:43,090 --> 00:06:46,570 +Now what is its projectedValue, +its dollar sign? + +146 +00:06:46,570 --> 00:06:50,430 +It's not a Publisher, +it's called a Binding. + +147 +00:06:50,430 --> 00:06:53,340 +We're gonna talk all about +Bindings in a couple slides here + +148 +00:06:53,340 --> 00:06:55,340 +but a Binding is essentially a way + +149 +00:06:55,340 --> 00:06:58,830 +to connect one var to another. + +150 +00:06:58,830 --> 00:07:02,470 +So taking the $ value of a State + +151 +00:07:02,470 --> 00:07:04,840 +let's you have an object that you can use + +152 +00:07:04,840 --> 00:07:08,350 +to bind to that value in the heap. + +153 +00:07:08,350 --> 00:07:10,833 +So we'll see what that +Binding means in a second. + +154 +00:07:11,920 --> 00:07:14,470 +Next one is ObservedObject. + +155 +00:07:14,470 --> 00:07:16,920 +What's the wrappedValue +of on ObservedObject? + +156 +00:07:16,920 --> 00:07:20,490 +It's anything that implements +the ObservableObject protocol, + +157 +00:07:20,490 --> 00:07:22,550 +ViewModels, basically. + +158 +00:07:22,550 --> 00:07:25,800 +What does @ObservedObject struct do? + +159 +00:07:25,800 --> 00:07:27,610 +Well, it invalidates the View + +160 +00:07:27,610 --> 00:07:29,850 +whenever the wrappedValue or the ViewModel + +161 +00:07:29,850 --> 00:07:32,220 +does objectWillChange.send. + +162 +00:07:32,220 --> 00:07:34,200 +Whenever that happens, +it redraws the View. + +163 +00:07:34,200 --> 00:07:36,420 +That's what ObservedObject does. + +164 +00:07:36,420 --> 00:07:39,450 +Now what's its projectedValue, +its dollar sign thing? + +165 +00:07:39,450 --> 00:07:42,880 +It's also a Binding, a Binding +to the vars of the ViewModel + +166 +00:07:44,170 --> 00:07:45,760 +which is really cool. + +167 +00:07:45,760 --> 00:07:48,800 +So you can bind a variable in your View + +168 +00:07:48,800 --> 00:07:51,350 +to a variable in the ViewModel + +169 +00:07:51,350 --> 00:07:54,233 +so that if either changes, +the other one gets updated. + +170 +00:07:55,170 --> 00:07:57,040 +And what about Binding itself? + +171 +00:07:57,040 --> 00:07:59,480 +So we haven't seen this one, @Binding, + +172 +00:07:59,480 --> 00:08:00,803 +it's a property wrapper. + +173 +00:08:01,720 --> 00:08:05,070 +The wrappedValue of @Binding is a value + +174 +00:08:05,070 --> 00:08:07,920 +that's bound to some other +thing somewhere else. + +175 +00:08:07,920 --> 00:08:11,340 +Like it's bound to the +vars of a ViewModel, + +176 +00:08:11,340 --> 00:08:15,000 +it's bound to an @State +in some other View. + +177 +00:08:15,000 --> 00:08:18,675 +An @Binding struct gets the +value and sets the value + +178 +00:08:18,675 --> 00:08:20,230 +of the wrappedValue by getting and setting + +179 +00:08:20,230 --> 00:08:22,250 +the value of this other thing. + +180 +00:08:22,250 --> 00:08:23,883 +It also invalidates the View. + +181 +00:08:24,870 --> 00:08:28,720 +So what is the +projectedValue of a Binding? + +182 +00:08:28,720 --> 00:08:33,010 +It's self, it's essentially +the Binding itself. + +183 +00:08:33,010 --> 00:08:36,540 +If you get the $ of a +var that's a Binding, + +184 +00:08:36,540 --> 00:08:39,200 +you're gonna be getting +that Binding itself back. + +185 +00:08:39,200 --> 00:08:41,690 +Or you can think of it +as it's a Binding to + +186 +00:08:41,690 --> 00:08:43,890 +the value that the Binding is bound to, + +187 +00:08:43,890 --> 00:08:45,583 +but it's essentially self. + +188 +00:08:46,710 --> 00:08:49,410 +Let's talk about these Bindings +more 'cause this is all new. + +189 +00:08:49,410 --> 00:08:50,720 +Where do we use Bindings? + +190 +00:08:50,720 --> 00:08:52,730 +We use 'em all over the place. + +191 +00:08:52,730 --> 00:08:54,150 +And I'm not even gonna +go through this list, + +192 +00:08:54,150 --> 00:08:56,490 +it's so exhaustive, there's so many things + +193 +00:08:56,490 --> 00:08:59,100 +we use for Bindings. + +194 +00:08:59,100 --> 00:09:01,900 +But I'm gonna talk about +why we have Bindings, + +195 +00:09:01,900 --> 00:09:04,730 +why we use them to do all these things. + +196 +00:09:04,730 --> 00:09:08,530 +Bindings are about one of +the most important things + +197 +00:09:08,530 --> 00:09:12,200 +in the MVVM reactive UI +structure of SwiftUI, + +198 +00:09:12,200 --> 00:09:15,677 +it's about having a single +source of the truth for data. + +199 +00:09:15,677 --> 00:09:18,500 +And that is so important. + +200 +00:09:18,500 --> 00:09:21,830 +If we have data in our Model, +it wants to live in our Model, + +201 +00:09:21,830 --> 00:09:25,560 +we do not want it duplicated +in our Views, right? + +202 +00:09:25,560 --> 00:09:29,080 +If we have information +in one View, in an @State + +203 +00:09:29,080 --> 00:09:31,627 +and we have information in +another View in its @State, + +204 +00:09:31,627 --> 00:09:34,100 +and if that's the same information, + +205 +00:09:34,100 --> 00:09:35,720 +they should be bound to each other + +206 +00:09:35,720 --> 00:09:39,170 +instead of one of them trying +to duplicate the other one + +207 +00:09:39,170 --> 00:09:41,150 +and, which one is the truth? + +208 +00:09:41,150 --> 00:09:42,340 +Can't tell. + +209 +00:09:42,340 --> 00:09:44,890 +So Bindings are about creating variables + +210 +00:09:44,890 --> 00:09:46,690 +that connect things together + +211 +00:09:46,690 --> 00:09:49,870 +so that only one place +has the actual truth. + +212 +00:09:49,870 --> 00:09:52,570 +And whether we're talking +about truth in the Model + +213 +00:09:52,570 --> 00:09:55,467 +or whether we're just talking +about truth in our Views + +214 +00:09:55,467 --> 00:09:58,080 +'cause we might have +temporary state in our Views, + +215 +00:09:58,080 --> 00:10:00,280 +we know we have that with @State, + +216 +00:10:00,280 --> 00:10:03,133 +we only want one source +of truth for that as well. + +217 +00:10:05,500 --> 00:10:08,250 +So, let's show you what I mean + +218 +00:10:08,250 --> 00:10:11,640 +when I say the source +of truth between Views. + +219 +00:10:11,640 --> 00:10:14,865 +So here I have a View MyView + +220 +00:10:14,865 --> 00:10:17,090 +and it's got some @States, some String, + +221 +00:10:17,090 --> 00:10:19,870 +myString it's called, +initialized to "Hello". + +222 +00:10:19,870 --> 00:10:20,960 +And then I have another View, + +223 +00:10:20,960 --> 00:10:23,840 +totally different View down at +the bottom there, OtherView, + +224 +00:10:23,840 --> 00:10:26,400 +and it has a var sharedText, + +225 +00:10:26,400 --> 00:10:29,590 +its body just shows that +sharedText to be a Text, + +226 +00:10:29,590 --> 00:10:33,300 +but that var is wrapped with @Binding. + +227 +00:10:33,300 --> 00:10:37,400 +So up above in MyView, it's +using an OtherView in its body + +228 +00:10:37,400 --> 00:10:39,080 +and of course when it +creates that OtherView + +229 +00:10:39,080 --> 00:10:42,010 +it has to initialize all +the uninitialized variables + +230 +00:10:42,010 --> 00:10:45,750 +in OtherView and the first +one is that var sharedText. + +231 +00:10:45,750 --> 00:10:47,970 +And what's the type of that sharedText? + +232 +00:10:47,970 --> 00:10:50,920 +It's a Binding to a String. + +233 +00:10:50,920 --> 00:10:54,210 +So how am I gonna pass +a Binding to a String? + +234 +00:10:54,210 --> 00:10:57,610 +I'm gonna use the $ of an @State. + +235 +00:10:57,610 --> 00:11:00,760 +I told you the $ of an +@State gives you a Binding + +236 +00:11:00,760 --> 00:11:02,260 +to that state's value. + +237 +00:11:02,260 --> 00:11:04,880 +So if I say $myString, I've got a Binding, + +238 +00:11:04,880 --> 00:11:09,321 +Capital B Binding, to +that String, myString. + +239 +00:11:09,321 --> 00:11:13,250 +Now, OtherView has that +String, MyView has that String, + +240 +00:11:13,250 --> 00:11:16,360 +but the source of truth +is MyView's version + +241 +00:11:16,360 --> 00:11:17,920 +and either of them can change it. + +242 +00:11:17,920 --> 00:11:20,370 +OtherView could change sharedText + +243 +00:11:20,370 --> 00:11:23,180 +and that would change myString in MyView, + +244 +00:11:23,180 --> 00:11:25,460 +and, of course, MyView +could change MyString + +245 +00:11:25,460 --> 00:11:27,990 +and it would show up inside OtherView. + +246 +00:11:27,990 --> 00:11:29,680 +So there's not a, you don't make a copy + +247 +00:11:29,680 --> 00:11:33,290 +when you create OtherView, +you actually bind it to it. + +248 +00:11:33,290 --> 00:11:35,400 +And we're gonna see +this in the demo today. + +249 +00:11:35,400 --> 00:11:39,810 +This is fundamental to +understanding how data flow works + +250 +00:11:39,810 --> 00:11:42,650 +in Swift is to understand we +want single source of truth + +251 +00:11:42,650 --> 00:11:44,823 +and we bind to get that. + +252 +00:11:45,920 --> 00:11:47,210 +You can also bind to other things. + +253 +00:11:47,210 --> 00:11:50,300 +You can bind to a constant +value by doing Binding.constant + +254 +00:11:50,300 --> 00:11:51,810 +and providing a value. + +255 +00:11:51,810 --> 00:11:55,690 +You can even compute the +value of the Binding, + +256 +00:11:55,690 --> 00:11:57,420 +in other words, execute a closure + +257 +00:11:57,420 --> 00:11:59,037 +when you try to get the value of a Binding + +258 +00:11:59,037 --> 00:12:01,500 +and then execute another +closure when you try to set it. + +259 +00:12:01,500 --> 00:12:04,400 +This feels a lot like computed properties. + +260 +00:12:04,400 --> 00:12:06,550 +That's kind of an advanced +topic, you won't have to do that + +261 +00:12:06,550 --> 00:12:09,080 +in this class ever, but I +just want you to understand + +262 +00:12:09,080 --> 00:12:11,870 +how Binding is working, +it's just hooking up + +263 +00:12:11,870 --> 00:12:15,060 +to some data and that data +could also be closures, + +264 +00:12:15,060 --> 00:12:18,850 +just like a computed +var's data is closures. + +265 +00:12:18,850 --> 00:12:21,100 +Let's talk about another property wrapper. + +266 +00:12:21,100 --> 00:12:23,470 +We know @State, we know @ObservedObject, + +267 +00:12:23,470 --> 00:12:25,360 +and now we know @Binding. + +268 +00:12:25,360 --> 00:12:27,950 +Here's another one, @EnvironmentObject. + +269 +00:12:29,179 --> 00:12:34,050 +@EnvironmentObject is almost +identical to @ObservedObject + +270 +00:12:34,960 --> 00:12:38,740 +but you pass the ViewModel to the View + +271 +00:12:38,740 --> 00:12:40,470 +in a little different way. + +272 +00:12:40,470 --> 00:12:43,520 +We know that, when we have a +View and it has a ViewModel, + +273 +00:12:43,520 --> 00:12:46,063 +we have a var which is an @ObservedObject, + +274 +00:12:47,110 --> 00:12:50,880 +and we usually initialize +it by passing it to the View + +275 +00:12:50,880 --> 00:12:52,530 +when we create the View. + +276 +00:12:52,530 --> 00:12:54,960 +We've done this with +the EmojiArt document, + +277 +00:12:54,960 --> 00:12:56,020 +we did it back in Memorize, + +278 +00:12:56,020 --> 00:12:59,300 +we actually called the thing +viewModel, kinda silly, + +279 +00:12:59,300 --> 00:13:01,260 +but that's how we were doing it. + +280 +00:13:01,260 --> 00:13:04,710 +So @EnvironmentObject +is doing the same thing, + +281 +00:13:04,710 --> 00:13:07,490 +it's holding your ViewModel in your View + +282 +00:13:07,490 --> 00:13:10,440 +but you pass it by calling this +function .environmentObject + +283 +00:13:11,810 --> 00:13:15,200 +with the ViewModel as the +argument, on the View. + +284 +00:13:15,200 --> 00:13:17,800 +So you're essentially +setting your ViewModel + +285 +00:13:17,800 --> 00:13:21,383 +with a ViewModifier if you +wanna think of it that way. + +286 +00:13:22,510 --> 00:13:23,850 +Now what's the difference +between these two? + +287 +00:13:23,850 --> 00:13:25,460 +Why do they have these two different ways + +288 +00:13:25,460 --> 00:13:27,690 +that kinda do the exact same thing? + +289 +00:13:27,690 --> 00:13:30,780 +Well, EnvironmentObjects +have this really cool feature + +290 +00:13:30,780 --> 00:13:34,250 +which is that all of +the Views in your body, + +291 +00:13:34,250 --> 00:13:36,700 +if you have an EnvironmentObject on you, + +292 +00:13:36,700 --> 00:13:38,970 +they all get that EnvironmentObject too + +293 +00:13:38,970 --> 00:13:41,850 +without your having to +say .environmentObject. + +294 +00:13:41,850 --> 00:13:45,132 +It's similar to, like if +we have .foregroundColor + +295 +00:13:45,132 --> 00:13:47,010 +on a ZStack, that's kind of like + +296 +00:13:47,010 --> 00:13:48,330 +we're calling .foregroundColor + +297 +00:13:48,330 --> 00:13:50,794 +on every single thing inside the ZStack. + +298 +00:13:50,794 --> 00:13:51,720 +That's not in fact what's happening + +299 +00:13:51,720 --> 00:13:53,450 +but it kinda feels like that. + +300 +00:13:53,450 --> 00:13:54,720 +Same thing here. + +301 +00:13:54,720 --> 00:13:56,740 +If you have an EnvironmentObject in a View + +302 +00:13:56,740 --> 00:13:58,380 +then it's like all the Views in this body + +303 +00:13:58,380 --> 00:14:01,070 +have .environmentObject on there. + +304 +00:14:01,070 --> 00:14:04,930 +There's a significant +exception, which is modal Views + +305 +00:14:04,930 --> 00:14:08,300 +and we're gonna talk about +modal Views a little later, + +306 +00:14:08,300 --> 00:14:10,970 +I don't know if next lecture +or maybe the one after, + +307 +00:14:10,970 --> 00:14:13,580 +but those kind of Views, popovers, alerts, + +308 +00:14:13,580 --> 00:14:15,720 +things like that, they +do not automatically + +309 +00:14:15,720 --> 00:14:17,873 +get the EnvironmentObject passed to them. + +310 +00:14:18,950 --> 00:14:22,339 +Another slight limitation +on EnvironmentObject + +311 +00:14:22,339 --> 00:14:25,710 +is that you can only have +one EnvironmentObject wrapper + +312 +00:14:25,710 --> 00:14:30,710 +per type of ViewModel in each View. + +313 +00:14:31,010 --> 00:14:34,110 +Not a huge restriction +but you couldn't have + +314 +00:14:34,110 --> 00:14:36,220 +two @EnvironmentObjects in the same View + +315 +00:14:36,220 --> 00:14:40,550 +that were both Memorize ViewModels. + +316 +00:14:40,550 --> 00:14:42,220 +We could have one that's +Memorize's ViewModel, + +317 +00:14:42,220 --> 00:14:43,750 +one that's EmojiArt ViewModel + +318 +00:14:43,750 --> 00:14:45,420 +but they couldn't both be the same. + +319 +00:14:45,420 --> 00:14:47,790 +So minor restriction there. + +320 +00:14:47,790 --> 00:14:50,620 +So let's give the EnvironmentObject +the same treatment + +321 +00:14:50,620 --> 00:14:51,660 +we gave the other ones. + +322 +00:14:51,660 --> 00:14:53,110 +What's its wrappedValue? + +323 +00:14:53,110 --> 00:14:57,260 +Same as ObservedObject, which +is, it's any ObservableObject, + +324 +00:14:57,260 --> 00:14:59,850 +but it's obtained with .environmentObject + +325 +00:14:59,850 --> 00:15:02,320 +instead of being passed as a var. + +326 +00:15:02,320 --> 00:15:05,320 +What does it do, this +EnvironmentObject struct? + +327 +00:15:05,320 --> 00:15:08,110 +It invalidates the View +when the wrappedValue + +328 +00:15:08,110 --> 00:15:09,600 +does objectWillChange.send, + +329 +00:15:09,600 --> 00:15:11,910 +exactly the same as ObservedObject. + +330 +00:15:11,910 --> 00:15:13,660 +And what's its projectedValue? + +331 +00:15:13,660 --> 00:15:15,370 +Again, the same as ObservedObject, + +332 +00:15:15,370 --> 00:15:18,880 +you can get at the vars of +your ViewModel with the $. + +333 +00:15:20,710 --> 00:15:24,370 +One more property wrapper +called @Environment. + +334 +00:15:24,370 --> 00:15:27,389 +This has nothing to do +with EnvironmentObject. + +335 +00:15:27,389 --> 00:15:28,620 +This is a totally different thing. + +336 +00:15:28,620 --> 00:15:29,910 +Clear your mind. + +337 +00:15:29,910 --> 00:15:32,920 +They have the same first word +but they're different things. + +338 +00:15:32,920 --> 00:15:36,310 +So get ready for something +totally different, ready? + +339 +00:15:36,310 --> 00:15:39,410 +First I have to explain to +you that property wrappers + +340 +00:15:39,410 --> 00:15:42,377 +can have more variables +even than the wrappedValue + +341 +00:15:42,377 --> 00:15:43,820 +and projectedValue. + +342 +00:15:43,820 --> 00:15:46,580 +Now, if you have more properties, +you might need to set them + +343 +00:15:46,580 --> 00:15:50,442 +just like we have unset +vars in other structs + +344 +00:15:50,442 --> 00:15:51,290 +we might have the same thing. + +345 +00:15:51,290 --> 00:15:53,490 +So how do you pass that in? + +346 +00:15:53,490 --> 00:15:56,410 +Well, when you create +your property wrapper + +347 +00:15:56,410 --> 00:16:01,410 +like @Environment, in +parentheses you put the vars. + +348 +00:16:01,920 --> 00:16:04,740 +Now, just like in any other struct, + +349 +00:16:04,740 --> 00:16:07,060 +you can get rid of the +label on the argument + +350 +00:16:07,060 --> 00:16:10,140 +that is quite possible +and Environment does this. + +351 +00:16:10,140 --> 00:16:11,900 +So Environment takes this one argument, + +352 +00:16:11,900 --> 00:16:14,730 +now, the argument there +that you're gonna give it + +353 +00:16:14,730 --> 00:16:17,350 +which it's gonna set one +of its internal vars with + +354 +00:16:17,350 --> 00:16:22,350 +is a key path into an +EnvironmentValues struct. + +355 +00:16:23,020 --> 00:16:26,030 +So you're just gonna +look EnvironmentValues up + +356 +00:16:26,030 --> 00:16:30,810 +in the documentation and you're +gonna see the long long list + +357 +00:16:30,810 --> 00:16:33,670 +of the things you can find +out about your Environment. + +358 +00:16:33,670 --> 00:16:36,660 +For example, here I'm using +the key path .colorScheme + +359 +00:16:38,031 --> 00:16:39,170 +and so EnvironmentValues.colorScheme + +360 +00:16:40,780 --> 00:16:43,870 +is the current light mode or dark mode + +361 +00:16:43,870 --> 00:16:47,393 +of the environment you're +running in essentially. + +362 +00:16:48,550 --> 00:16:51,729 +Now, note that the color scheme up there, + +363 +00:16:51,729 --> 00:16:54,400 +@Environment colorScheme, +it says var colorScheme, + +364 +00:16:54,400 --> 00:16:56,040 +it doesn't say the type. + +365 +00:16:56,040 --> 00:16:58,180 +There's no colon anything up there. + +366 +00:16:58,180 --> 00:17:00,610 +And it is perfectly allowed +for a property wrapper + +367 +00:17:00,610 --> 00:17:04,490 +to have the wrappedValue's +type be set internally. + +368 +00:17:04,490 --> 00:17:06,170 +And that's what Environment does + +369 +00:17:06,170 --> 00:17:09,220 +and it sets the type of the var there, + +370 +00:17:09,220 --> 00:17:13,480 +colorScheme in that case, +to whatever is the type + +371 +00:17:13,480 --> 00:17:16,240 +of the key path that you're passing to it. + +372 +00:17:16,240 --> 00:17:19,180 +So for example, colorScheme +in environmentValues + +373 +00:17:19,180 --> 00:17:22,940 +is of type ColorScheme, +capital C, capital S, + +374 +00:17:22,940 --> 00:17:25,637 +which is an enum and that +enum just has two values, + +375 +00:17:25,637 --> 00:17:27,570 +.dark and .light. + +376 +00:17:27,570 --> 00:17:29,310 +That just tells you +whether you're in dark mode + +377 +00:17:29,310 --> 00:17:30,719 +or light mode right now. + +378 +00:17:30,719 --> 00:17:32,130 +So that's really great 'cause +when you're drawing your View + +379 +00:17:32,130 --> 00:17:34,540 +you can know what mode you're in. + +380 +00:17:34,540 --> 00:17:36,500 +Then there are dozens of other things. + +381 +00:17:36,500 --> 00:17:39,030 +It's all about the +EnvironmentValues struct. + +382 +00:17:39,030 --> 00:17:42,020 +Go take a look at there and +you, yes you can even have + +383 +00:17:42,020 --> 00:17:44,550 +your own ones, we're not +gonna talk about how to do it, + +384 +00:17:44,550 --> 00:17:46,770 +it is possible, using extensions, + +385 +00:17:46,770 --> 00:17:50,600 +to add environment values +to EnvironmentValues. + +386 +00:17:50,600 --> 00:17:51,960 +Again the same treatment, + +387 +00:17:51,960 --> 00:17:54,330 +what is the wrappedValue of Environment? + +388 +00:17:54,330 --> 00:17:58,300 +It is the value of some +var in EnvironmentValues. + +389 +00:17:58,300 --> 00:18:01,050 +And what does environment +do, that struct do + +390 +00:18:01,050 --> 00:18:02,250 +when you get and set? + +391 +00:18:02,250 --> 00:18:05,200 +It sets and gets that +value in EnvironmentValues. + +392 +00:18:05,200 --> 00:18:07,300 +And what is its projectedValue? + +393 +00:18:07,300 --> 00:18:08,560 +None. + +394 +00:18:08,560 --> 00:18:12,750 +Property wrappers are allowed +to have no projectedValue + +395 +00:18:12,750 --> 00:18:15,583 +and @Environment indeed +has no projectedValue. + +396 +00:18:19,040 --> 00:18:20,650 +Publisher. + +397 +00:18:20,650 --> 00:18:24,290 +So, again, Publisher, very deep +topic, a lot to talk about. + +398 +00:18:24,290 --> 00:18:25,970 +We are not going to take all the time + +399 +00:18:25,970 --> 00:18:26,820 +we would talk about today. + +400 +00:18:26,820 --> 00:18:28,430 +I'm just gonna give you +the light treatment, + +401 +00:18:28,430 --> 00:18:30,720 +the overview so you get an idea + +402 +00:18:30,720 --> 00:18:32,713 +of generally what this is all about. + +403 +00:18:34,010 --> 00:18:36,580 +So Publisher is +conceptually really simple. + +404 +00:18:36,580 --> 00:18:40,250 +Its declaration will +look something like this. + +405 +00:18:40,250 --> 00:18:43,360 +Publisher with two don't +cares, the blue Output, + +406 +00:18:43,360 --> 00:18:45,140 +the red Failure there. + +407 +00:18:45,140 --> 00:18:47,480 +And the output is just some type + +408 +00:18:47,480 --> 00:18:50,330 +that this Publisher periodically emits. + +409 +00:18:50,330 --> 00:18:53,680 +It publishes it out into the world. + +410 +00:18:53,680 --> 00:18:57,650 +And the failure is the type +of struct or information + +411 +00:18:57,650 --> 00:19:01,420 +that it gives if it should fail to publish + +412 +00:19:01,420 --> 00:19:02,640 +for whatever reason. + +413 +00:19:02,640 --> 00:19:04,400 +Maybe it's publishing +something from over the network + +414 +00:19:04,400 --> 00:19:05,900 +and the network connection goes dead + +415 +00:19:05,900 --> 00:19:09,510 +and it has to fail and tell +you what happened, for example. + +416 +00:19:09,510 --> 00:19:12,730 +A common failure is the failure Never, + +417 +00:19:12,730 --> 00:19:14,680 +you see the green Never right there. + +418 +00:19:14,680 --> 00:19:17,580 +And that failure means, I don't ever fail, + +419 +00:19:17,580 --> 00:19:20,810 +I publish my values, +la-la-la, I'm publishing them + +420 +00:19:20,810 --> 00:19:23,020 +and I never fail, nothing can go wrong + +421 +00:19:23,020 --> 00:19:24,790 +that would cause me to fail. + +422 +00:19:24,790 --> 00:19:27,660 +And that's quite a common failure mode. + +423 +00:19:27,660 --> 00:19:28,493 +What can we do with a Publisher? + +424 +00:19:28,493 --> 00:19:30,440 +We've got a Publisher +and we know it publishes + +425 +00:19:30,440 --> 00:19:32,540 +a certain type of thing +and that it might fail + +426 +00:19:32,540 --> 00:19:35,530 +with a certain kind of failure, +what can we do with it? + +427 +00:19:35,530 --> 00:19:38,270 +Well the number one thing +we do with Publishers, + +428 +00:19:38,270 --> 00:19:39,730 +is we listen to them. + +429 +00:19:39,730 --> 00:19:41,027 +We listen to the values +that are publishing + +430 +00:19:41,027 --> 00:19:42,930 +and we do something with the values. + +431 +00:19:42,930 --> 00:19:46,083 +That's why Publishers exist, +so we can listen to them. + +432 +00:19:47,270 --> 00:19:50,240 +But we also often are +transforming the values + +433 +00:19:50,240 --> 00:19:52,660 +that are coming out of +a Publisher on the fly, + +434 +00:19:52,660 --> 00:19:55,550 +taking actions, converting +it to publish something + +435 +00:19:55,550 --> 00:19:58,520 +slightly different than +it would usually publish, + +436 +00:19:58,520 --> 00:20:00,450 +to kinda massage it into something + +437 +00:20:00,450 --> 00:20:03,590 +that periodically gives +us what we really want. + +438 +00:20:03,590 --> 00:20:07,130 +So a lot of the API Publisher +is about transforming it + +439 +00:20:07,130 --> 00:20:09,060 +and we can also shuttle its values + +440 +00:20:09,060 --> 00:20:12,583 +kind of off into other places +as well as they're coming out. + +441 +00:20:14,170 --> 00:20:15,640 +There's a lot more, but again, + +442 +00:20:15,640 --> 00:20:17,310 +I'm not gonna be talking about anything + +443 +00:20:17,310 --> 00:20:18,783 +but the basics today. + +444 +00:20:20,180 --> 00:20:22,080 +So let's talk about +listening to a Publisher, + +445 +00:20:22,080 --> 00:20:23,370 +we call that subscribing. + +446 +00:20:23,370 --> 00:20:26,190 +There's a whole protocol +called Subscriber. + +447 +00:20:26,190 --> 00:20:28,150 +And I'm only gonna talk about two ways + +448 +00:20:28,150 --> 00:20:29,480 +to subscribe to a Publisher, + +449 +00:20:29,480 --> 00:20:33,060 +two of the most common +ways out there to do it. + +450 +00:20:33,060 --> 00:20:36,080 +One is to execute a closure + +451 +00:20:36,080 --> 00:20:38,720 +whenever the Publisher publishes its data + +452 +00:20:38,720 --> 00:20:40,890 +or when it finishes, +either 'cause it failed + +453 +00:20:40,890 --> 00:20:42,750 +or it just completed normally. + +454 +00:20:42,750 --> 00:20:45,230 +And the name of this function is .sink, + +455 +00:20:45,230 --> 00:20:48,650 +this is a function on +a Publisher, say .sink, + +456 +00:20:48,650 --> 00:20:49,715 +and it has two arguments, + +457 +00:20:49,715 --> 00:20:51,758 +receiveCompletion, which takes a closure, + +458 +00:20:51,758 --> 00:20:54,168 +and receiveValue which takes a closure. + +459 +00:20:54,168 --> 00:20:58,566 +The receiveCompletion closure +is given the completion enum. + +460 +00:20:58,566 --> 00:21:00,710 +The completion enum +basically has two states, + +461 +00:21:00,710 --> 00:21:02,010 +it succeeded or it failed + +462 +00:21:02,010 --> 00:21:03,940 +and if it failed it's +got the associated value + +463 +00:21:03,940 --> 00:21:07,070 +of whatever the failure information is. + +464 +00:21:07,070 --> 00:21:09,230 +And then receiveValue, it's just a closure + +465 +00:21:09,230 --> 00:21:11,840 +that takes whatever just last got emitted. + +466 +00:21:11,840 --> 00:21:14,093 +So as the Publisher emits its value, + +467 +00:21:14,093 --> 00:21:15,750 +it's constantly emitting them, + +468 +00:21:15,750 --> 00:21:19,400 +this receiveValue closure +is constantly being called + +469 +00:21:19,400 --> 00:21:20,990 +until it fails or completes + +470 +00:21:20,990 --> 00:21:23,100 +and then the other one gets called. + +471 +00:21:23,100 --> 00:21:24,810 +Now one thing to note here is that + +472 +00:21:24,810 --> 00:21:28,810 +if the Publisher's failure +is Never, so it never fails, + +473 +00:21:28,810 --> 00:21:30,010 +then you can call sink + +474 +00:21:30,010 --> 00:21:32,250 +without specifying that receiveCompletion, + +475 +00:21:32,250 --> 00:21:34,980 +because it's never going to +call your receiveCompletion + +476 +00:21:34,980 --> 00:21:37,270 +'cause it never completes, never fails, + +477 +00:21:37,270 --> 00:21:39,143 +so you can just skip that. + +478 +00:21:40,270 --> 00:21:42,453 +And that's a common thing to do, again. + +479 +00:21:44,360 --> 00:21:47,330 +Notice that sink here returns something + +480 +00:21:47,330 --> 00:21:48,750 +and I've made it in purple + +481 +00:21:48,750 --> 00:21:51,360 +because it's actually quite important. + +482 +00:21:51,360 --> 00:21:52,920 +This thing that it returns, + +483 +00:21:52,920 --> 00:21:55,680 +implements this Cancellable protocol, + +484 +00:21:55,680 --> 00:21:58,200 +which is a very simple protocol, + +485 +00:21:58,200 --> 00:22:00,540 +but very often it gets type erased + +486 +00:22:00,540 --> 00:22:03,100 +and sink does this where +it type erases the return + +487 +00:22:03,100 --> 00:22:04,750 +to be AnyCancellable. + +488 +00:22:04,750 --> 00:22:06,560 +This is just like we do +with transitions, right + +489 +00:22:06,560 --> 00:22:09,350 +where we have AnyTransition to +make it easier to deal with, + +490 +00:22:09,350 --> 00:22:10,183 +same thing here. + +491 +00:22:10,183 --> 00:22:13,000 +So sink returns an AnyCancellable. + +492 +00:22:13,000 --> 00:22:15,770 +What is the purpose of this +purple thing that we get back + +493 +00:22:15,770 --> 00:22:18,720 +from the sink function? + +494 +00:22:18,720 --> 00:22:19,780 +Well, two purposes. + +495 +00:22:19,780 --> 00:22:22,230 +Number one, you can send .cancel to it, + +496 +00:22:22,230 --> 00:22:25,310 +that's what's in the +Cancellable protocol, .cancel, + +497 +00:22:25,310 --> 00:22:27,870 +and if you call a cancel +function on this purple thing + +498 +00:22:27,870 --> 00:22:29,830 +then it'll stop sinking, + +499 +00:22:29,830 --> 00:22:32,400 +that sink will stop executing +the closures in there, + +500 +00:22:32,400 --> 00:22:33,630 +so it then goes away, + +501 +00:22:33,630 --> 00:22:36,400 +stops subscribing to that +Publisher essentially. + +502 +00:22:36,400 --> 00:22:37,360 +So that's valuable. + +503 +00:22:37,360 --> 00:22:39,300 +A little surprised that we +don't do that that often + +504 +00:22:39,300 --> 00:22:41,220 +but it's still valuable. + +505 +00:22:41,220 --> 00:22:46,220 +But B is the big deal, in +that it keeps .sink alive. + +506 +00:22:46,500 --> 00:22:50,880 +So as long as that var cancellable exists + +507 +00:22:50,880 --> 00:22:52,683 +then sink keeps sinking. + +508 +00:22:53,800 --> 00:22:57,430 +So cancellable would never +be a local variable here. + +509 +00:22:57,430 --> 00:22:58,740 +If you made that a local variable + +510 +00:22:58,740 --> 00:23:01,040 +then as soon as the method finishes, + +511 +00:23:01,040 --> 00:23:02,710 +the function that you're in finishes, + +512 +00:23:02,710 --> 00:23:05,050 +the sink would stop sinking. + +513 +00:23:05,050 --> 00:23:08,280 +This cancellable almost always +is going to be a property + +514 +00:23:08,280 --> 00:23:11,290 +an instance variable +on a struct or a class + +515 +00:23:11,290 --> 00:23:13,700 +and that's gonna make this sink last + +516 +00:23:13,700 --> 00:23:16,980 +as long as that struct or class lasts + +517 +00:23:16,980 --> 00:23:19,180 +'cause as soon as that +struct or class goes away, + +518 +00:23:19,180 --> 00:23:21,830 +not used any more, then +its vars, of course, + +519 +00:23:21,830 --> 00:23:22,910 +go away with it + +520 +00:23:22,910 --> 00:23:25,027 +and when its var is one +of these cancellables + +521 +00:23:25,027 --> 00:23:26,180 +and it goes away, + +522 +00:23:26,180 --> 00:23:28,330 +the sink will stop +listening to the Publisher + +523 +00:23:28,330 --> 00:23:30,980 +which is kind of exactly what you want. + +524 +00:23:30,980 --> 00:23:34,190 +So the return value of +sink is used to cancel + +525 +00:23:34,190 --> 00:23:37,840 +but even more importantly in +a way, it's used to decide + +526 +00:23:37,840 --> 00:23:41,260 +how long the sink keeps +listening to the Publisher. + +527 +00:23:41,260 --> 00:23:43,940 +And as long as that var exists somewhere, + +528 +00:23:43,940 --> 00:23:45,390 +it's going to keep listening. + +529 +00:23:46,930 --> 00:23:49,730 +We talked about sink as one +way to listen to a Publisher. + +530 +00:23:49,730 --> 00:23:52,970 +Another way is for a View +to listen to a Publisher. + +531 +00:23:52,970 --> 00:23:54,520 +This is super simple. + +532 +00:23:54,520 --> 00:23:58,780 +There is a ViewModifier +on View called .onReceive, + +533 +00:23:58,780 --> 00:24:02,090 +you give it the Publisher and a closure + +534 +00:24:02,090 --> 00:24:03,380 +and that argument to closure + +535 +00:24:03,380 --> 00:24:05,610 +is the thing the Publisher emits, + +536 +00:24:05,610 --> 00:24:07,110 +and this closure will be called + +537 +00:24:07,110 --> 00:24:09,020 +every time that Publisher publishes + +538 +00:24:09,020 --> 00:24:12,860 +and your View will get +invalidated causing it to redraw. + +539 +00:24:12,860 --> 00:24:15,420 +This is an awesome little function. + +540 +00:24:15,420 --> 00:24:18,610 +Great way to hook your View +up to some source of data + +541 +00:24:18,610 --> 00:24:20,560 +and every time that data gets published + +542 +00:24:20,560 --> 00:24:22,408 +whoo, your View does something. + +543 +00:24:22,408 --> 00:24:24,030 +You know, you put any +code you want in there + +544 +00:24:24,030 --> 00:24:27,000 +in the do whatever you want part of that + +545 +00:24:27,000 --> 00:24:28,780 +and then you also get redrawn. + +546 +00:24:28,780 --> 00:24:31,543 +It's just a fantastic little feature. + +547 +00:24:33,010 --> 00:24:34,220 +Where do Publishers come from? + +548 +00:24:34,220 --> 00:24:35,900 +How do I get a hold of a Publisher? + +549 +00:24:35,900 --> 00:24:38,030 +They sound great but where do I get one? + +550 +00:24:38,030 --> 00:24:40,140 +Well there's a lot of places to get one. + +551 +00:24:40,140 --> 00:24:42,500 +I'll talk about a few of +the most common ones here. + +552 +00:24:42,500 --> 00:24:47,500 +One is to $, projectedValue, +of an @Published. + +553 +00:24:48,660 --> 00:24:50,700 +Okay, you have ViewModel that's publishing + +554 +00:24:50,700 --> 00:24:54,610 +a bunch of its vars and you can use the $ + +555 +00:24:54,610 --> 00:24:57,860 +to get a Publisher and find +out when things are changing. + +556 +00:24:57,860 --> 00:24:58,693 +And we're gonna do this the demo, + +557 +00:24:58,693 --> 00:25:01,630 +this is a very, probably +the most common source + +558 +00:25:01,630 --> 00:25:04,640 +in your Views of getting a Publisher. + +559 +00:25:04,640 --> 00:25:06,760 +But some other objects have this as well. + +560 +00:25:06,760 --> 00:25:10,550 +URLSession has one, we talked +briefly about what that is, + +561 +00:25:10,550 --> 00:25:13,070 +that's for getting data off the network. + +562 +00:25:13,070 --> 00:25:15,110 +Essentially as a Publisher, +you give it a URL + +563 +00:25:15,110 --> 00:25:17,800 +and it publishes the data +that it goes and fetches + +564 +00:25:17,800 --> 00:25:20,170 +when it's ready, that's pretty cool. + +565 +00:25:20,170 --> 00:25:21,780 +Timer is another one. + +566 +00:25:21,780 --> 00:25:25,290 +Timer, its Publisher will +publish the current date and time + +567 +00:25:25,290 --> 00:25:27,270 +every how ever often you say. + +568 +00:25:27,270 --> 00:25:29,530 +So you can have it publish +the current date and time + +569 +00:25:29,530 --> 00:25:32,800 +as a Date object, that's its publish type, + +570 +00:25:32,800 --> 00:25:35,670 +every tenth of a second, +every hundredth of a second, + +571 +00:25:35,670 --> 00:25:37,610 +every hour, whatever you want + +572 +00:25:37,610 --> 00:25:40,630 +and it'll just publish periodically. + +573 +00:25:40,630 --> 00:25:42,760 +There's also another thing +called NotificationCenter. + +574 +00:25:42,760 --> 00:25:45,410 +It tells you about things +going on in the system, + +575 +00:25:45,410 --> 00:25:47,440 +when things happen in the system + +576 +00:25:47,440 --> 00:25:48,880 +and you can set up a Publisher there + +577 +00:25:48,880 --> 00:25:51,700 +and it will publish these +things called notifications + +578 +00:25:51,700 --> 00:25:53,330 +and you can find out what's going on. + +579 +00:25:53,330 --> 00:25:56,083 +So that's another pretty +cool Publisher out there. + +580 +00:25:58,010 --> 00:25:59,240 +So there's a lot more stuff we can do. + +581 +00:25:59,240 --> 00:26:01,100 +Like I said, my goal today, + +582 +00:26:01,100 --> 00:26:02,440 +in both these slides and the demo, + +583 +00:26:02,440 --> 00:26:04,870 +is just to give you a flavor +for what a Publisher is. + +584 +00:26:04,870 --> 00:26:07,610 +I'm not gonna exhaustively +talk about the dozens + +585 +00:26:07,610 --> 00:26:09,850 +and dozens of methods +that are in Publisher, + +586 +00:26:09,850 --> 00:26:13,120 +I certainly recommend you +go look up the documentation + +587 +00:26:13,120 --> 00:26:14,860 +for Publisher and just +take a look in there, + +588 +00:26:14,860 --> 00:26:16,330 +just so you get a feel of what's in there + +589 +00:26:16,330 --> 00:26:18,430 +'cause there's a lot of stuff in there. + +590 +00:26:18,430 --> 00:26:20,960 +And hopefully the demo +that I'm just about to do, + +591 +00:26:20,960 --> 00:26:22,890 +which is gonna do some +stuff with Publisher, + +592 +00:26:22,890 --> 00:26:24,310 +will give you a more concrete feel + +593 +00:26:24,310 --> 00:26:27,040 +of how we use these +little data Publishers. + +594 +00:26:27,040 --> 00:26:31,930 +And by the way, Publisher +also is in the same service + +595 +00:26:31,930 --> 00:26:33,930 +of the single source of truth. + +596 +00:26:33,930 --> 00:26:36,230 +The Publisher wants to +be publishing the data + +597 +00:26:36,230 --> 00:26:38,700 +that is coming from the +actual source of the data + +598 +00:26:38,700 --> 00:26:40,500 +and then the consumers +are just consuming it + +599 +00:26:40,500 --> 00:26:42,530 +on the fly as it gets published. + +600 +00:26:42,530 --> 00:26:45,023 +So it's really part of +that effort as well. + +601 +00:26:47,070 --> 00:26:48,840 +So let's dive into that demo. + +602 +00:26:48,840 --> 00:26:51,390 +And you can read here what I'm gonna do + +603 +00:26:51,390 --> 00:26:54,373 +but it's mostly about +Publishers and Bindings. + +604 +00:26:55,240 --> 00:26:57,840 +But we're gonna start +by fixing a little bit + +605 +00:26:57,840 --> 00:27:00,540 +of a sloppiness in our UI. + +606 +00:27:00,540 --> 00:27:03,630 +I'm gonna run the app here EmojiArt + +607 +00:27:03,630 --> 00:27:06,600 +and I want you to watch +closely when it first launches + +608 +00:27:06,600 --> 00:27:08,370 +that it'll start with a white background + +609 +00:27:08,370 --> 00:27:11,290 +because it has to load +its background image + +610 +00:27:11,290 --> 00:27:14,530 +but while it's doing that, it's +still showing all the emoji + +611 +00:27:14,530 --> 00:27:16,610 +that go on that document. + +612 +00:27:16,610 --> 00:27:18,220 +And I think that looks pretty bad. + +613 +00:27:18,220 --> 00:27:19,580 +So let's take a look at that. + +614 +00:27:19,580 --> 00:27:20,760 +See, there we go. + +615 +00:27:20,760 --> 00:27:22,770 +And then it appears. + +616 +00:27:22,770 --> 00:27:24,771 +So really we don't want it to do this. + +617 +00:27:24,771 --> 00:27:26,690 +And this happen every +time we add a new image. + +618 +00:27:26,690 --> 00:27:28,150 +If I change the image to this, + +619 +00:27:28,150 --> 00:27:31,930 +we get this momentary white +background with the emoji. + +620 +00:27:31,930 --> 00:27:34,370 +So I really only wanna show these emoji + +621 +00:27:34,370 --> 00:27:37,123 +when this is loaded. + +622 +00:27:38,100 --> 00:27:42,833 +So, how am I going to +detect that situation? + +623 +00:27:43,730 --> 00:27:44,620 +It quite simple. + +624 +00:27:44,620 --> 00:27:46,720 +Just gonna go to my View over here. + +625 +00:27:46,720 --> 00:27:50,240 +This is the ForEach where +I show all of my emoji. + +626 +00:27:50,240 --> 00:27:53,523 +I'm just gonna say, if I'm not loading, + +627 +00:27:55,360 --> 00:27:57,513 +then go ahead and show my emoji. + +628 +00:28:00,660 --> 00:28:05,090 +So how do I know that I'm +loading my background image? + +629 +00:28:05,090 --> 00:28:08,080 +Pretty straight forward +to detect, actually. + +630 +00:28:08,080 --> 00:28:12,510 +Var isLoading is a Bool and +I'm just going to return + +631 +00:28:12,510 --> 00:28:17,510 +whether my document has +a backgroundURL set on it + +632 +00:28:21,070 --> 00:28:25,747 +and if my document does +not have a backgroundImage. + +633 +00:28:27,130 --> 00:28:30,740 +This tells me that I'm +loading, right, I have a URL + +634 +00:28:30,740 --> 00:28:33,190 +for a background, so I don't +have a blank background + +635 +00:28:33,190 --> 00:28:37,320 +and I don't have my image +yet, so I must be loading it. + +636 +00:28:37,320 --> 00:28:41,520 +Now, we didn't actually make +backgroundURL be gettable. + +637 +00:28:41,520 --> 00:28:44,700 +If you remember in our +ViewModel here, backgroundURL, + +638 +00:28:44,700 --> 00:28:47,930 +we have a set but this +is not a gettable var, + +639 +00:28:47,930 --> 00:28:48,870 +so let's fix that. + +640 +00:28:48,870 --> 00:28:52,119 +Let's make this just +a normal computed var, + +641 +00:28:52,119 --> 00:28:53,903 +backgroundURL, type URL. + +642 +00:28:55,337 --> 00:28:57,560 +And this is just the setter, + +643 +00:28:57,560 --> 00:28:59,490 +so we'll put a set in there. + +644 +00:28:59,490 --> 00:29:01,540 +Of course we're setting from the newValue + +645 +00:29:03,970 --> 00:29:06,700 +and then our getter is also simple, + +646 +00:29:06,700 --> 00:29:09,913 +that's just the emojiArt's backgroundURL. + +647 +00:29:12,890 --> 00:29:16,510 +Now that our View is able +to look at the backgroundURL + +648 +00:29:16,510 --> 00:29:20,070 +and obviously it can already +look at backgroundImage, + +649 +00:29:20,070 --> 00:29:23,113 +it can easily detect whether +we're in the middle of loading. + +650 +00:29:24,480 --> 00:29:26,030 +We still have one more thing to do + +651 +00:29:26,030 --> 00:29:28,920 +which is that, since we +changed backgroundURL + +652 +00:29:28,920 --> 00:29:31,710 +to a computed property, yeah, here we go, + +653 +00:29:31,710 --> 00:29:34,130 +this is where we set the backgroundURL, + +654 +00:29:34,130 --> 00:29:38,963 +now we have to say, +backgroundURL equals that url. + +655 +00:29:40,320 --> 00:29:43,140 +I think that's all that we have to do. + +656 +00:29:43,140 --> 00:29:44,290 +Let's go ahead and run. + +657 +00:29:47,394 --> 00:29:49,660 +Ah ho, it was white before it loaded + +658 +00:29:49,660 --> 00:29:52,310 +and let's go pick our very large document, + +659 +00:29:52,310 --> 00:29:54,010 +this one takes a little while to load, + +660 +00:29:54,010 --> 00:29:58,560 +here we go, boom, woo, nice, nice. + +661 +00:29:58,560 --> 00:30:00,350 +But what would be even nicer + +662 +00:30:00,350 --> 00:30:02,960 +is if we gave a little bit +of feedback to the user, + +663 +00:30:02,960 --> 00:30:06,800 +Hey I'm loading that URL, +just give me a second. + +664 +00:30:06,800 --> 00:30:08,190 +And we can easily do that, + +665 +00:30:08,190 --> 00:30:12,170 +just by putting some sort of +image or animating graphic + +666 +00:30:12,170 --> 00:30:16,020 +or something up while we're +in that loading stage. + +667 +00:30:16,020 --> 00:30:18,860 +So just here, where we do +if not loading is this, + +668 +00:30:18,860 --> 00:30:22,990 +we could just as easily +also have, if loading, + +669 +00:30:22,990 --> 00:30:26,500 +then do something, like +put up some kind of image, + +670 +00:30:26,500 --> 00:30:29,530 +or we'll put our emoji, in the other case. + +671 +00:30:29,530 --> 00:30:31,330 +So, what kind of image +do you wanna use here? + +672 +00:30:31,330 --> 00:30:34,120 +Let's go ahead and do +this systemName stuff + +673 +00:30:34,120 --> 00:30:37,170 +that I talked about in the slides. + +674 +00:30:37,170 --> 00:30:39,040 +And this allows us to specify the name + +675 +00:30:39,040 --> 00:30:40,420 +of one of the system images + +676 +00:30:40,420 --> 00:30:41,950 +and we're gonna go look those up. + +677 +00:30:41,950 --> 00:30:45,060 +I'm also gonna make the +imageScale be large here, + +678 +00:30:45,060 --> 00:30:48,100 +can make this image kinda +as large as it can be. + +679 +00:30:48,100 --> 00:30:50,340 +These images are not huge images. + +680 +00:30:50,340 --> 00:30:54,480 +They're mostly intended +to be embedded near text + +681 +00:30:54,480 --> 00:30:56,890 +so they try to be about +the same size as text, + +682 +00:30:56,890 --> 00:31:00,160 +so this is mostly just trying +to match up with large text, + +683 +00:31:00,160 --> 00:31:02,300 +but we don't really +need a huge image here. + +684 +00:31:02,300 --> 00:31:03,420 +And if we wanted something huge, + +685 +00:31:03,420 --> 00:31:05,030 +we could just create our own shape + +686 +00:31:05,030 --> 00:31:08,490 +and maybe cool animated +thing that shows loading, + +687 +00:31:08,490 --> 00:31:10,050 +but we're just gonna do +something simple here + +688 +00:31:10,050 --> 00:31:12,820 +which is this system image. + +689 +00:31:12,820 --> 00:31:14,610 +Now how do we find these system images? + +690 +00:31:14,610 --> 00:31:19,610 +You'll remember, we go to +developer.apple.com/design + +691 +00:31:19,820 --> 00:31:23,200 +and we download this app called SF Symbols + +692 +00:31:23,200 --> 00:31:26,810 +and it has tons and +tons and tons of symbols + +693 +00:31:26,810 --> 00:31:27,810 +that we could use. + +694 +00:31:27,810 --> 00:31:30,100 +And they're even put +into groups over here. + +695 +00:31:30,100 --> 00:31:33,100 +We're trying to do a timer, I +see one called time down here, + +696 +00:31:33,100 --> 00:31:34,364 +let's look at that. + +697 +00:31:34,364 --> 00:31:37,720 +Hmmm, this is an interesting +one, maybe timer right there + +698 +00:31:37,720 --> 00:31:40,700 +would be a good one and +this is its exact name + +699 +00:31:40,700 --> 00:31:44,083 +so we can just go back in +here and put that name, timer, + +700 +00:31:45,350 --> 00:31:46,630 +and run. + +701 +00:31:46,630 --> 00:31:50,690 +Let's see if we get a +little timer, oh, we got it, + +702 +00:31:50,690 --> 00:31:52,500 +it was there for a little bit. + +703 +00:31:52,500 --> 00:31:55,860 +Let's go load another image up here. + +704 +00:31:55,860 --> 00:31:57,930 +Yeah, it puts a little timer there. + +705 +00:31:57,930 --> 00:31:59,717 +Now, that little static timer though, + +706 +00:31:59,717 --> 00:32:01,960 +that's not very pretty. + +707 +00:32:01,960 --> 00:32:03,840 +It's kinda boring. + +708 +00:32:03,840 --> 00:32:05,360 +It'd be nice, maybe, if we had something + +709 +00:32:05,360 --> 00:32:07,460 +that's animated there. + +710 +00:32:07,460 --> 00:32:10,626 +Wouldn't it be cool if we +could just say something like + +711 +00:32:10,626 --> 00:32:14,960 +.spinning, that would just +have a View modification + +712 +00:32:14,960 --> 00:32:18,370 +to make whatever this View is be spinning. + +713 +00:32:18,370 --> 00:32:21,050 +Well, unfortunately, +there is no such thing. + +714 +00:32:21,050 --> 00:32:22,860 +It would be nice to have +one but there isn't, + +715 +00:32:22,860 --> 00:32:25,500 +so we're just gonna make one ourselves. + +716 +00:32:25,500 --> 00:32:29,100 +Go here new file, this is +gonna be a ViewModifier, right, + +717 +00:32:29,100 --> 00:32:30,750 +that spinning is a ViewModifier, + +718 +00:32:30,750 --> 00:32:32,260 +I'm gonna call it Spinning, + +719 +00:32:32,260 --> 00:32:34,943 +that's gonna be the name +of the modifier itself, + +720 +00:32:36,200 --> 00:32:40,290 +and it's, of course, +UI, and it's a struct, + +721 +00:32:40,290 --> 00:32:44,610 +Spinning, which is a ViewModifier. + +722 +00:32:44,610 --> 00:32:49,610 +And ViewModifiers have func +body which takes some content + +723 +00:32:50,220 --> 00:32:54,510 +of some don't care type +that returns some View + +724 +00:32:54,510 --> 00:32:56,640 +and we then just modify this + +725 +00:32:56,640 --> 00:33:01,245 +with whatever things we wanna +do to make it the way we want. + +726 +00:33:01,245 --> 00:33:02,800 +We clearly want some rotation effect + +727 +00:33:02,800 --> 00:33:04,430 +'cause we want it to spin, + +728 +00:33:04,430 --> 00:33:06,560 +we saw that animation before. + +729 +00:33:06,560 --> 00:33:11,010 +Let's make an Angle +here with degrees being, + +730 +00:33:11,010 --> 00:33:13,630 +well, when this thing +is visible on screen, + +731 +00:33:13,630 --> 00:33:17,170 +let's say we'll make it go over to 360 + +732 +00:33:17,170 --> 00:33:19,960 +otherwise zero degrees. + +733 +00:33:19,960 --> 00:33:22,400 +Now how do we know if it's visible? + +734 +00:33:22,400 --> 00:33:25,060 +Well, we're gonna have to +have some state for that. + +735 +00:33:25,060 --> 00:33:27,840 +Now you know this is just a state struct, + +736 +00:33:27,840 --> 00:33:31,444 +it takes whatever var we +put here, like isVisible, + +737 +00:33:31,444 --> 00:33:34,160 +which is just a Bool, and +it stores it in the heap + +738 +00:33:34,160 --> 00:33:37,510 +and keeps it in the heap +even if this View is rebuilt. + +739 +00:33:37,510 --> 00:33:39,800 +But we are gonna have to set +that thing when we appear, + +740 +00:33:39,800 --> 00:33:43,610 +so onAppear, I'm gonna +say, self.isVisible = true + +741 +00:33:45,240 --> 00:33:46,960 +and the other thing we need to do + +742 +00:33:46,960 --> 00:33:49,160 +is put some implicit animation. + +743 +00:33:49,160 --> 00:33:50,650 +So let's do that, animation + +744 +00:33:52,210 --> 00:33:56,330 +animation.linear, put a duration, + +745 +00:33:56,330 --> 00:33:58,900 +maybe one second to go all the way around, + +746 +00:33:58,900 --> 00:34:01,860 +and of course it wants to repeat forever + +747 +00:34:01,860 --> 00:34:04,613 +and it does not want to autoreverse. + +748 +00:34:06,350 --> 00:34:08,440 +I don't think we ever +need to stop this thing + +749 +00:34:08,440 --> 00:34:09,470 +once it comes on screen. + +750 +00:34:09,470 --> 00:34:11,480 +We'll just let it spin and spin. + +751 +00:34:11,480 --> 00:34:13,943 +It's making it so this +View is always spinning. + +752 +00:34:14,830 --> 00:34:18,860 +And let's also put our +nice extension on View + +753 +00:34:18,860 --> 00:34:20,860 +so that we have this func spinning + +754 +00:34:20,860 --> 00:34:23,750 +that we can just put on as a ViewModifier, + +755 +00:34:23,750 --> 00:34:27,720 +and return some View of +course which is our self + +756 +00:34:27,720 --> 00:34:30,123 +modified with Spinning. + +757 +00:34:31,120 --> 00:34:33,600 +Hopefully you're getting +pretty comfortable now + +758 +00:34:33,600 --> 00:34:35,687 +with these ViewModifiers. + +759 +00:34:37,307 --> 00:34:38,140 +So watch carefully, + +760 +00:34:38,140 --> 00:34:39,540 +'cause it's only gonna spin +a short amount of time. + +761 +00:34:39,540 --> 00:34:41,000 +Uh there, I saw it spinning. + +762 +00:34:41,000 --> 00:34:42,000 +I saw it spinning. + +763 +00:34:42,000 --> 00:34:43,800 +Let's load something else. + +764 +00:34:43,800 --> 00:34:47,060 +Woop, that was so fast, you +couldn't even see it spinning. + +765 +00:34:47,060 --> 00:34:49,270 +How about this one, we +know this is a big one, + +766 +00:34:49,270 --> 00:34:51,890 +let's try this, uh, it's pretty good. + +767 +00:34:51,890 --> 00:34:54,950 +And we could pick other images, maybe, + +768 +00:34:54,950 --> 00:34:57,130 +I actually looked around and one I thought + +769 +00:34:57,130 --> 00:34:59,610 +that was kinda cool, I was +searching time-based thing + +770 +00:34:59,610 --> 00:35:01,670 +and I found hourglass. + +771 +00:35:01,670 --> 00:35:03,450 +So I think hourglass looks pretty cool, + +772 +00:35:03,450 --> 00:35:04,650 +let's put that in there. + +773 +00:35:05,950 --> 00:35:07,200 +See what that looks like. + +774 +00:35:10,845 --> 00:35:11,678 +Hmm, yeah. + +775 +00:35:11,678 --> 00:35:14,050 +Kinda like little spinning hourglass. + +776 +00:35:14,050 --> 00:35:16,930 +So, giving that kind of feedback +to users is always good. + +777 +00:35:16,930 --> 00:35:21,020 +You never really want your +application's reaction + +778 +00:35:21,020 --> 00:35:24,690 +to the user doing something to +be that just nothing happens. + +779 +00:35:24,690 --> 00:35:26,830 +Because then the user's +not sure you really heard + +780 +00:35:26,830 --> 00:35:29,940 +what it was asking, what the +user was asking you to do. + +781 +00:35:29,940 --> 00:35:32,833 +So giving feedback back like +that always a good idea. + +782 +00:35:34,030 --> 00:35:35,940 +So let's dive into this Publishers thing + +783 +00:35:35,940 --> 00:35:39,210 +which is our main, one of +our two main topics today. + +784 +00:35:39,210 --> 00:35:41,850 +And the first thing I'm +gonna do with Publishers + +785 +00:35:41,850 --> 00:35:44,470 +is go back here where +we did this work-around + +786 +00:35:44,470 --> 00:35:46,270 +for property observers not really working + +787 +00:35:46,270 --> 00:35:47,960 +with property wrappers + +788 +00:35:47,960 --> 00:35:50,470 +and we made this whole business here. + +789 +00:35:50,470 --> 00:35:53,680 +And I'm gonna undo this, +just get rid of this + +790 +00:35:53,680 --> 00:35:54,680 +whole thing + +791 +00:35:55,560 --> 00:36:00,000 +and I'm gonna take our +Published and put it back + +792 +00:36:00,000 --> 00:36:01,547 +so we're not doing that work around + +793 +00:36:01,547 --> 00:36:04,510 +and we're gonna do it in +a totally different way. + +794 +00:36:04,510 --> 00:36:08,180 +What we're gonna do is +use the projectedValue + +795 +00:36:08,180 --> 00:36:12,007 +of our Published struct, +remember that's the $emojiArt, + +796 +00:36:13,300 --> 00:36:16,580 +that is a Publisher, and in specific, + +797 +00:36:16,580 --> 00:36:19,350 +it's a Publisher of EmojiArts. + +798 +00:36:19,350 --> 00:36:21,470 +So every time this EmojiArt changes, + +799 +00:36:21,470 --> 00:36:24,690 +it publishes this EmojiArt again. + +800 +00:36:24,690 --> 00:36:26,570 +And that is very valuable for us + +801 +00:36:26,570 --> 00:36:28,880 +because every time this EmojiArt changes + +802 +00:36:28,880 --> 00:36:30,483 +we want to autosave. + +803 +00:36:32,920 --> 00:36:35,490 +So let's just set that up in our init. + +804 +00:36:36,376 --> 00:36:40,650 +I'm gonna use that $emojiArt +which is the Publisher, + +805 +00:36:40,650 --> 00:36:43,840 +and I'm going to use that +thing we talked about + +806 +00:36:43,840 --> 00:36:47,710 +which is being able to sink the Publisher + +807 +00:36:47,710 --> 00:36:48,740 +to a function. + +808 +00:36:48,740 --> 00:36:51,740 +Now, there's two versions +of this sink right here. + +809 +00:36:51,740 --> 00:36:53,670 +This one takes two arguments, + +810 +00:36:53,670 --> 00:36:56,210 +receiveCompletion and receiveValue. + +811 +00:36:56,210 --> 00:36:59,230 +Both of them are closures. + +812 +00:36:59,230 --> 00:37:02,940 +The first one is passing +you a completion enum + +813 +00:37:02,940 --> 00:37:05,993 +and it's saying, this +Publisher finished publishing. + +814 +00:37:06,870 --> 00:37:11,870 +Now, our $ Published Publishers +don't ever send completions + +815 +00:37:12,170 --> 00:37:14,070 +'cause they just are always publishing, + +816 +00:37:14,070 --> 00:37:15,910 +they don't really ever stop. + +817 +00:37:15,910 --> 00:37:20,130 +So they're completion +failure type is Never, + +818 +00:37:20,130 --> 00:37:22,470 +capital N, Never, that +is their failure type, + +819 +00:37:22,470 --> 00:37:25,010 +they Never fail because they can't fail + +820 +00:37:25,010 --> 00:37:27,230 +and also they don't complete. + +821 +00:37:27,230 --> 00:37:28,990 +When you have that kind of Publisher + +822 +00:37:28,990 --> 00:37:31,660 +that doesn't specify any kind of failure, + +823 +00:37:31,660 --> 00:37:33,800 +then you can use this +simple version of sink + +824 +00:37:33,800 --> 00:37:35,300 +that just gives you the values. + +825 +00:37:35,300 --> 00:37:38,190 +And you can see that +receiveValue right there, + +826 +00:37:38,190 --> 00:37:41,410 +is just a closure that takes the thing + +827 +00:37:41,410 --> 00:37:44,630 +that the Publisher publishes +which is an emjoiArt + +828 +00:37:44,630 --> 00:37:45,940 +and returns nothing. + +829 +00:37:45,940 --> 00:37:49,490 +So that means a closure takes an EmojiArt + +830 +00:37:49,490 --> 00:37:51,387 +and we can do whatever we want in here + +831 +00:37:51,387 --> 00:37:53,460 +and what I want to do in here is + +832 +00:37:53,460 --> 00:37:57,920 +put it in to UserDefaults, autosave it. + +833 +00:37:57,920 --> 00:38:02,820 +Let's go ahead and print +our EmojiArt's json. + +834 +00:38:06,170 --> 00:38:08,840 +Well this way we'll be +able to see the json + +835 +00:38:08,840 --> 00:38:10,200 +that's going on there. + +836 +00:38:10,200 --> 00:38:11,500 +Notice that we have an error here + +837 +00:38:11,500 --> 00:38:15,220 +or a warning, anyway, result +of call to sink is unused. + +838 +00:38:15,220 --> 00:38:17,890 +And that's actually very bad, okay. + +839 +00:38:17,890 --> 00:38:22,890 +Really you never want the +result of sink not to be used. + +840 +00:38:23,410 --> 00:38:26,740 +So sink is what we call a Subscriber. + +841 +00:38:26,740 --> 00:38:29,880 +It's subscribing to what's going on + +842 +00:38:29,880 --> 00:38:33,350 +in this Publisher right here, +right, it wants to find out, + +843 +00:38:33,350 --> 00:38:35,960 +listen to what the +Publisher is publishing. + +844 +00:38:35,960 --> 00:38:39,070 +So Subscribers, when you +create them, they almost always + +845 +00:38:39,070 --> 00:38:42,273 +are gonna give you what's +called a Cancellable. + +846 +00:38:43,920 --> 00:38:45,580 +It has two functions, right? + +847 +00:38:45,580 --> 00:38:48,700 +You can cancel but also +it keeps it around. + +848 +00:38:48,700 --> 00:38:50,560 +So if I were to do the code like this, + +849 +00:38:50,560 --> 00:38:52,510 +let cancellable equal this, + +850 +00:38:52,510 --> 00:38:54,780 +not only is cancellable never used, + +851 +00:38:54,780 --> 00:38:58,150 +but when init ends, this is a local var, + +852 +00:38:58,150 --> 00:39:01,323 +it gets thrown out and so would this sink. + +853 +00:39:02,250 --> 00:39:06,230 +So if we want this sink +to live past the execution + +854 +00:39:06,230 --> 00:39:09,367 +of this init, we need to do private var, + +855 +00:39:11,132 --> 00:39:12,267 +let's call this our autosaveCancellable + +856 +00:39:15,620 --> 00:39:18,553 +and it's gonna be of type AnyCancellable. + +857 +00:39:19,420 --> 00:39:21,770 +And this AnyCancellable right here, + +858 +00:39:21,770 --> 00:39:25,673 +is just a type-erased version +of the Cancellable for this + +859 +00:39:25,673 --> 00:39:27,940 +and the Cancellable for this + +860 +00:39:27,940 --> 00:39:31,350 +really encapsulates all the +things this Subscriber is doing + +861 +00:39:31,350 --> 00:39:32,920 +in subscribing to this Publisher. + +862 +00:39:32,920 --> 00:39:34,270 +So it can be kinda complicated, + +863 +00:39:34,270 --> 00:39:37,157 +it's got all the output +value of the Publisher + +864 +00:39:37,157 --> 00:39:39,017 +and the failure and all that is in there. + +865 +00:39:39,017 --> 00:39:41,250 +And we just want it to be a simple var + +866 +00:39:41,250 --> 00:39:44,440 +that we can store to so it +gets type-erased for us. + +867 +00:39:44,440 --> 00:39:48,710 +Sink type-erases whatever +this Cancellable stuff is + +868 +00:39:48,710 --> 00:39:50,500 +so that we get this AnyCancellable, + +869 +00:39:50,500 --> 00:39:52,793 +exactly the same as we +did for AnyTransition. + +870 +00:39:54,450 --> 00:39:55,920 +Now notice we got a bad error here, + +871 +00:39:55,920 --> 00:39:59,580 +use of undeclared type AnyCancellable. + +872 +00:39:59,580 --> 00:40:01,220 +Why is this undeclared? + +873 +00:40:01,220 --> 00:40:03,280 +Because all of this Publisher stuff + +874 +00:40:03,280 --> 00:40:08,270 +comes from a different +framework called Combine. + +875 +00:40:08,270 --> 00:40:09,970 +And so the Combine framework + +876 +00:40:09,970 --> 00:40:12,520 +has the Cancellable, +subscribing, publishing, + +877 +00:40:12,520 --> 00:40:14,173 +all that stuff comes from there. + +878 +00:40:15,450 --> 00:40:19,250 +All we need to do to keep this sink around + +879 +00:40:19,250 --> 00:40:21,367 +is to assign its Cancellable to this var + +880 +00:40:21,367 --> 00:40:23,830 +that's in our ViewModel + +881 +00:40:23,830 --> 00:40:26,320 +and it'll live as long as +the ViewModel does right now. + +882 +00:40:26,320 --> 00:40:28,150 +Once this ViewModel goes away, of course, + +883 +00:40:28,150 --> 00:40:30,760 +this var will go away with it +and then the sink will stop. + +884 +00:40:30,760 --> 00:40:34,010 +Now, in our app, our +ViewModel never goes away + +885 +00:40:34,010 --> 00:40:36,630 +but it's quite possible to +have ViewModels disappearing. + +886 +00:40:36,630 --> 00:40:38,450 +If you have an app that +has multiple screens + +887 +00:40:38,450 --> 00:40:40,417 +you might have a ViewModel +that's in charge of one screen + +888 +00:40:40,417 --> 00:40:41,930 +and when that screen goes away, + +889 +00:40:41,930 --> 00:40:43,820 +ha, the ViewModel goes away too. + +890 +00:40:43,820 --> 00:40:46,200 +And that's perfect, we wouldn't +want this to be autosaving + +891 +00:40:46,200 --> 00:40:48,200 +when this ViewModel's not around. + +892 +00:40:48,200 --> 00:40:51,180 +So this is a really nice way to link up + +893 +00:40:51,180 --> 00:40:55,493 +this Subscriber to whatever +object it's helping out. + +894 +00:40:56,390 --> 00:40:58,528 +Let's go ahead and run +and see if we're getting + +895 +00:40:58,528 --> 00:41:01,310 +this json printed out on our console. + +896 +00:41:01,310 --> 00:41:02,907 +Make a little room so we can see + +897 +00:41:02,907 --> 00:41:05,010 +and we can already see that it did like, + +898 +00:41:05,010 --> 00:41:07,730 +it looks like, yeah, an initial autosave + +899 +00:41:07,730 --> 00:41:11,400 +when we first brought this document up. + +900 +00:41:11,400 --> 00:41:13,330 +And let's make a change to our document, + +901 +00:41:13,330 --> 00:41:16,920 +I'm gonna add, let's see, a pretzel, doop, + +902 +00:41:16,920 --> 00:41:18,180 +and now we have two pretzels, + +903 +00:41:18,180 --> 00:41:19,780 +maybe we'll add another pretzel. + +904 +00:41:21,090 --> 00:41:23,420 +Now we have three +pretzels, one, two, three. + +905 +00:41:23,420 --> 00:41:25,203 +So our autosave is working. + +906 +00:41:28,120 --> 00:41:31,220 +Let's do another thing +exactly like that, actually + +907 +00:41:31,220 --> 00:41:33,700 +because we have another +Published right here, + +908 +00:41:33,700 --> 00:41:36,003 +our backgroundImage is Published. + +909 +00:41:36,003 --> 00:41:38,150 +What about this cool feature? + +910 +00:41:38,150 --> 00:41:39,363 +Let's go back here. + +911 +00:41:40,310 --> 00:41:42,990 +When I add a new background, + +912 +00:41:42,990 --> 00:41:45,800 +let's say like this background right here, + +913 +00:41:45,800 --> 00:41:47,210 +lemme drag this background, + +914 +00:41:47,210 --> 00:41:48,670 +watch what happens. + +915 +00:41:48,670 --> 00:41:51,240 +Okay, it didn't quite fit the edges + +916 +00:41:51,240 --> 00:41:54,470 +and it's even worse if I do a bigger one + +917 +00:41:54,470 --> 00:41:57,233 +right here like this, this guy. + +918 +00:42:00,860 --> 00:42:03,550 +We really want this +like double tap to zoom + +919 +00:42:03,550 --> 00:42:06,250 +to happen automatically whenever +we set our background image + +920 +00:42:06,250 --> 00:42:08,090 +to something else. + +921 +00:42:08,090 --> 00:42:10,140 +And we'll go back and set it to this one. + +922 +00:42:12,000 --> 00:42:14,870 +Boop, that's terrible, we'd +really like it to go like that. + +923 +00:42:14,870 --> 00:42:17,820 +So we already have this +nice function, zoomToFit, + +924 +00:42:17,820 --> 00:42:19,230 +it would just be great if every time + +925 +00:42:19,230 --> 00:42:22,690 +our backgroundImage changed +we called zoomToFit. + +926 +00:42:22,690 --> 00:42:24,510 +Well, that's quite easy to do, too + +927 +00:42:24,510 --> 00:42:27,210 +because we know when our +backgroundImage gets set, + +928 +00:42:27,210 --> 00:42:28,960 +it's when this var gets set, + +929 +00:42:28,960 --> 00:42:33,220 +and this is a Published, so +there's a $backgroundImage var + +930 +00:42:33,220 --> 00:42:35,997 +which is a Publisher +that publishes this image + +931 +00:42:35,997 --> 00:42:38,623 +and we can use that in our View. + +932 +00:42:39,580 --> 00:42:41,460 +So let's go look in our View over here + +933 +00:42:41,460 --> 00:42:43,241 +and see how we would do that. + +934 +00:42:43,241 --> 00:42:45,990 +Just gonna go, let's say down here + +935 +00:42:45,990 --> 00:42:49,887 +and say, .onReceive, so +onReceive is how we do that + +936 +00:42:49,887 --> 00:42:54,170 +and we say self.document.$backgroundImage, + +937 +00:42:54,170 --> 00:42:56,090 +that's the backgroundImage Publisher, + +938 +00:42:56,090 --> 00:42:59,320 +that's going to call a +closure with the thing + +939 +00:42:59,320 --> 00:43:01,680 +that got published when this was received + +940 +00:43:01,680 --> 00:43:04,832 +so that's the UIImage +that got published here + +941 +00:43:04,832 --> 00:43:09,730 +and I'm gonna say, +self.zoomToFit that Image + +942 +00:43:09,730 --> 00:43:12,893 +in our geometry.size. + +943 +00:43:14,850 --> 00:43:15,683 +That's it. + +944 +00:43:16,635 --> 00:43:19,640 +So now every time this thing publishes + +945 +00:43:19,640 --> 00:43:20,820 +because a new image came in, + +946 +00:43:20,820 --> 00:43:23,660 +you can even see the +very first one does it. + +947 +00:43:23,660 --> 00:43:25,580 +Let's go down here and make another image, + +948 +00:43:25,580 --> 00:43:27,283 +how about this one, + +949 +00:43:30,150 --> 00:43:31,250 +loading, that's nice, + +950 +00:43:31,250 --> 00:43:32,373 +and it zoomed to fit. + +951 +00:43:33,370 --> 00:43:35,940 +So those Publishers really really valuable + +952 +00:43:35,940 --> 00:43:39,410 +to hook up to and you'll get +the hang of those $ things + +953 +00:43:39,410 --> 00:43:40,690 +and like, hmmm, that's really cool. + +954 +00:43:40,690 --> 00:43:43,660 +I wanna know when that +changed, I'll do onReceive + +955 +00:43:43,660 --> 00:43:47,853 +or I'll go in here and hook +up a sink to it, for example. + +956 +00:43:50,040 --> 00:43:52,670 +But there's more things +we can do with Publishers + +957 +00:43:52,670 --> 00:43:55,597 +than just these $ things +with the Published. + +958 +00:43:55,597 --> 00:43:57,950 +I'm gonna use a Publisher to do + +959 +00:43:57,950 --> 00:44:00,310 +this whole backgroundImage fetch. + +960 +00:44:00,310 --> 00:44:03,200 +When we were doing this, +I kinda mentioned that + +961 +00:44:03,200 --> 00:44:06,130 +really we want to do this with +the class called URLSession + +962 +00:44:06,130 --> 00:44:09,300 +because URLSession +knows how to do timeouts + +963 +00:44:09,300 --> 00:44:11,920 +and all the setup and +everything having to do with it. + +964 +00:44:11,920 --> 00:44:15,560 +We really were just using +Data contentsOf, right here, + +965 +00:44:15,560 --> 00:44:18,600 +which is kind of a dumb, not so smart, + +966 +00:44:18,600 --> 00:44:21,530 +non-configurable way to fetch things. + +967 +00:44:21,530 --> 00:44:23,860 +So let's use URLSession here + +968 +00:44:23,860 --> 00:44:26,180 +to do this background fetch instead. + +969 +00:44:26,180 --> 00:44:29,350 +And that is going to be +done with a Publisher. + +970 +00:44:29,350 --> 00:44:32,310 +So first, how do we get +a session, a URLSession? + +971 +00:44:32,310 --> 00:44:34,310 +We just say, URLSession + +972 +00:44:34,310 --> 00:44:38,347 +and it does have some +initializers that you can see, + +973 +00:44:38,347 --> 00:44:42,197 +say this configuration and you +can configure your URLSession + +974 +00:44:43,200 --> 00:44:45,200 +to have whatever timeout here you want. + +975 +00:44:45,200 --> 00:44:48,180 +But it also has a nice one called shared. + +976 +00:44:48,180 --> 00:44:51,130 +That's a static var, a shared URLSession + +977 +00:44:51,130 --> 00:44:52,450 +that your whole app can use + +978 +00:44:52,450 --> 00:44:54,920 +when it just wants to do simple downloads. + +979 +00:44:54,920 --> 00:44:56,080 +And we'll use this one a lot + +980 +00:44:56,080 --> 00:44:57,610 +when we're doing straightforward download, + +981 +00:44:57,610 --> 00:45:00,330 +where we don't care about +the timeout, whatever, + +982 +00:45:00,330 --> 00:45:02,600 +but we still want all the wonderfulness + +983 +00:45:02,600 --> 00:45:04,273 +that URLSession does. + +984 +00:45:05,400 --> 00:45:09,350 +Now, how do we ask URLSession +to download something + +985 +00:45:09,350 --> 00:45:12,520 +from a URL and how does it give it to us? + +986 +00:45:12,520 --> 00:45:14,280 +Well, it does this with a Publisher. + +987 +00:45:14,280 --> 00:45:18,990 +So I'm gonna say, let +publisher equal our session + +988 +00:45:18,990 --> 00:45:23,413 +it has this great function, +dataTaskPublisher for url. + +989 +00:45:24,819 --> 00:45:27,130 +And this is going to give us a Publisher + +990 +00:45:27,130 --> 00:45:29,030 +and we all know what a Publisher is, + +991 +00:45:29,030 --> 00:45:32,260 +that is going to publish +the contents of this URL + +992 +00:45:32,260 --> 00:45:34,337 +whatever it wants it goes +out and fetches this, + +993 +00:45:34,337 --> 00:45:35,710 +and publishes it. + +994 +00:45:35,710 --> 00:45:38,870 +And let's take a closer look +actually at Publisher here + +995 +00:45:38,870 --> 00:45:40,000 +in the documentation. + +996 +00:45:40,000 --> 00:45:42,050 +This Publisher that URLSession creates, + +997 +00:45:42,050 --> 00:45:45,573 +is called a DataTaskPublisher, +lemme click on it, + +998 +00:45:46,430 --> 00:45:50,060 +go in here, and we know +that Publishers have Output, + +999 +00:45:50,060 --> 00:45:53,060 +don't care, and a Failure don't care. + +1000 +00:45:53,060 --> 00:45:56,170 +So let's look at URLSession's +Output don't care, + +1001 +00:45:56,170 --> 00:45:59,120 +what does it turn that +Output don't care into? + +1002 +00:45:59,120 --> 00:46:03,400 +It makes it into a tuple +with the Data it got back + +1003 +00:46:03,400 --> 00:46:06,060 +and this thing called a URLResponse + +1004 +00:46:06,060 --> 00:46:08,623 +which is stuff like +the suggested file name + +1005 +00:46:08,623 --> 00:46:10,440 +that it found on the other side, + +1006 +00:46:10,440 --> 00:46:14,500 +and kinda URL-y oriented things, + +1007 +00:46:14,500 --> 00:46:16,360 +but this is usually what +we're most interested in + +1008 +00:46:16,360 --> 00:46:18,873 +is this data that came back from that URL. + +1009 +00:46:19,990 --> 00:46:20,823 +Well, that's cool. + +1010 +00:46:20,823 --> 00:46:22,030 +And what about this Failure? + +1011 +00:46:22,030 --> 00:46:24,193 +What happens when one of these URLSession + +1012 +00:46:24,193 --> 00:46:26,030 +DataTaskPublishers fails, + +1013 +00:46:26,030 --> 00:46:29,410 +like network connection's +not available or whatever? + +1014 +00:46:29,410 --> 00:46:32,240 +Well, it's type is URLError, remember, + +1015 +00:46:32,240 --> 00:46:35,130 +this is a don't care and +we're saying what type it is + +1016 +00:46:35,130 --> 00:46:36,920 +for this particular Publisher. + +1017 +00:46:36,920 --> 00:46:39,260 +So it's URLError, let's look at URLError, + +1018 +00:46:39,260 --> 00:46:40,340 +here it is. + +1019 +00:46:40,340 --> 00:46:42,900 +And it has things you +might suspect, again, + +1020 +00:46:42,900 --> 00:46:45,260 +you know, little localized +description right here + +1021 +00:46:45,260 --> 00:46:48,113 +of what happens, some error +codes, that kind of thing. + +1022 +00:46:48,990 --> 00:46:51,090 +So that's what most Publishers look like, + +1023 +00:46:51,090 --> 00:46:52,520 +they just have some output, + +1024 +00:46:52,520 --> 00:46:56,000 +like that tuple of Data in the response, + +1025 +00:46:56,000 --> 00:46:58,300 +and then also they have +some Failure possibly. + +1026 +00:46:59,220 --> 00:47:01,360 +Now, again, remember that +these Published guys, + +1027 +00:47:01,360 --> 00:47:04,000 +they don't have a Failure, +their Failure is Never + +1028 +00:47:04,000 --> 00:47:06,400 +'cause they don't ever +fail, they just keep on, + +1029 +00:47:06,400 --> 00:47:07,663 +keep on keepin' on. + +1030 +00:47:09,920 --> 00:47:13,100 +This Publisher is not +publishing exactly what we want, + +1031 +00:47:13,100 --> 00:47:14,400 +we don't really want a tuple, + +1032 +00:47:14,400 --> 00:47:16,380 +what we want is an image, okay? + +1033 +00:47:16,380 --> 00:47:18,730 +We want, we'd be great if this Publisher + +1034 +00:47:18,730 --> 00:47:21,930 +would take our URL and just +publish an image to us. + +1035 +00:47:21,930 --> 00:47:23,640 +Then we would be able to put our image + +1036 +00:47:23,640 --> 00:47:27,069 +into our backgroundImage up here, + +1037 +00:47:27,069 --> 00:47:29,260 +everything would work perfectly. + +1038 +00:47:29,260 --> 00:47:32,680 +And so, one of the main +ways that we use Publishers + +1039 +00:47:32,680 --> 00:47:34,890 +is we take an existing Publisher + +1040 +00:47:34,890 --> 00:47:39,890 +and we kinda slowly coerce it +into doing the things we want. + +1041 +00:47:39,990 --> 00:47:43,690 +And that is done by +creating new Publishers. + +1042 +00:47:43,690 --> 00:47:45,130 +So I'm gonna take this Publisher + +1043 +00:47:45,130 --> 00:47:47,820 +and I'm gonna send it a message called map + +1044 +00:47:47,820 --> 00:47:51,800 +and map takes a closure that +gives you the information + +1045 +00:47:51,800 --> 00:47:54,550 +in the existing Publisher + +1046 +00:47:54,550 --> 00:47:58,520 +which for us is the +Data and the URLResponse + +1047 +00:48:00,086 --> 00:48:03,980 +and it lets you return the +type you'd rather it be. + +1048 +00:48:03,980 --> 00:48:06,090 +And I'd rather this be a UIImage. + +1049 +00:48:07,391 --> 00:48:08,660 +And how do I make it? + +1050 +00:48:08,660 --> 00:48:12,730 +Take the Data that you pass me and map it. + +1051 +00:48:12,730 --> 00:48:15,760 +Now this Publisher is +no longer a Publisher + +1052 +00:48:15,760 --> 00:48:20,010 +that returns that tuple +and has an error, URLError. + +1053 +00:48:20,010 --> 00:48:22,560 +Instead it has been +mapped to be a Publisher + +1054 +00:48:22,560 --> 00:48:24,720 +that publishes a UIImage + +1055 +00:48:24,720 --> 00:48:26,660 +and this is actually Optional UIImage + +1056 +00:48:26,660 --> 00:48:29,690 +'cause this is a failable initializer, + +1057 +00:48:29,690 --> 00:48:32,045 +so it publishes Optional UIImage + +1058 +00:48:32,045 --> 00:48:34,870 +and it still has the URLError Failure. + +1059 +00:48:34,870 --> 00:48:38,550 +So we just mapped this Publisher +into a different Publisher. + +1060 +00:48:38,550 --> 00:48:41,330 +In some ways Publishers +feel a lot like Arrays + +1061 +00:48:41,330 --> 00:48:44,940 +because, you know, an Array +is like a list of values + +1062 +00:48:44,940 --> 00:48:47,040 +and a Publisher is kind +of a list of values + +1063 +00:48:47,040 --> 00:48:48,040 +but it's over time, + +1064 +00:48:48,040 --> 00:48:49,640 +the Publisher's publishing over time. + +1065 +00:48:49,640 --> 00:48:54,420 +So a lot of the functions in +Publisher mimic those in Array. + +1066 +00:48:54,420 --> 00:48:57,870 +So that's great, so it's +publishing UIImages for us + +1067 +00:48:57,870 --> 00:48:59,020 +but there's a problem. + +1068 +00:48:59,020 --> 00:49:01,970 +URLSession does all of its work + +1069 +00:49:01,970 --> 00:49:04,240 +in one of those global background queues + +1070 +00:49:04,240 --> 00:49:06,370 +because, of course, you +don't wanna block the UI + +1071 +00:49:06,370 --> 00:49:08,350 +while you're fetching these things. + +1072 +00:49:08,350 --> 00:49:12,410 +So we want this Publisher +not to publish these UIImages + +1073 +00:49:12,410 --> 00:49:13,680 +on those background threads + +1074 +00:49:13,680 --> 00:49:15,690 +which is what it would do by default. + +1075 +00:49:15,690 --> 00:49:18,330 +So we want it to publish this stuff + +1076 +00:49:18,330 --> 00:49:20,200 +on the main queue. + +1077 +00:49:20,200 --> 00:49:21,340 +And we can do that as well. + +1078 +00:49:21,340 --> 00:49:26,340 +We say, .receive on DispatchQueue.main + +1079 +00:49:28,390 --> 00:49:30,930 +and that turns this, +this returns a Publisher, + +1080 +00:49:30,930 --> 00:49:35,130 +a different Publisher, a +Publisher that publishes UIImages + +1081 +00:49:35,130 --> 00:49:38,250 +from this Publisher being converted there + +1082 +00:49:38,250 --> 00:49:41,050 +and publishes them on the main queue. + +1083 +00:49:41,050 --> 00:49:43,120 +So it's just slightly modified. + +1084 +00:49:43,120 --> 00:49:46,540 +Does this feel a lot like +Views and ViewModifiers? + +1085 +00:49:46,540 --> 00:49:49,180 +It's the same kind of design, +totally different system here + +1086 +00:49:49,180 --> 00:49:51,530 +because these are not UI things at all, + +1087 +00:49:51,530 --> 00:49:52,960 +but it's the same kind of idea + +1088 +00:49:52,960 --> 00:49:55,550 +where you're taking a +Publisher and modifying it, + +1089 +00:49:55,550 --> 00:49:56,383 +modifying it. + +1090 +00:49:56,383 --> 00:49:58,560 +Same way as a View, modify it, modify it. + +1091 +00:49:58,560 --> 00:49:59,633 +Exact same thing. + +1092 +00:50:01,330 --> 00:50:03,110 +Now the last thing we wanna do, + +1093 +00:50:03,110 --> 00:50:05,060 +this is pretty much in shape + +1094 +00:50:05,060 --> 00:50:08,430 +the kind of Publisher we want +is publishing UIImages to it, + +1095 +00:50:08,430 --> 00:50:11,970 +is we would like to maybe +use .sink or something + +1096 +00:50:11,970 --> 00:50:14,900 +like if I try to use .sink +here it's gonna be interesting, + +1097 +00:50:14,900 --> 00:50:16,310 +notice I didn't even get + +1098 +00:50:16,310 --> 00:50:19,450 +the sink option that only takes the value, + +1099 +00:50:19,450 --> 00:50:21,720 +right, the .sink that we used up here + +1100 +00:50:21,720 --> 00:50:23,980 +only just takes whatever it's publishing, + +1101 +00:50:23,980 --> 00:50:25,050 +there's no error here + +1102 +00:50:25,050 --> 00:50:28,080 +because, again, these Published things, + +1103 +00:50:28,080 --> 00:50:29,750 +their error is Never. + +1104 +00:50:29,750 --> 00:50:32,830 +So it's no use handling a Never error. + +1105 +00:50:32,830 --> 00:50:36,530 +So we don't even get this +option down here below. + +1106 +00:50:36,530 --> 00:50:41,370 +Why does this not even give +us the option for that? + +1107 +00:50:41,370 --> 00:50:44,320 +Well, our Publisher, this +publishing UIImages here, + +1108 +00:50:44,320 --> 00:50:47,333 +is still having the failure of URLError. + +1109 +00:50:48,480 --> 00:50:50,120 +I don't really want to handle errors. + +1110 +00:50:50,120 --> 00:50:52,810 +If I did I might well use sink right here. + +1111 +00:50:52,810 --> 00:50:53,920 +But I don't wanna handle errors. + +1112 +00:50:53,920 --> 00:50:57,240 +All I really wanna do is +just give me that UIImage + +1113 +00:50:57,240 --> 00:51:00,080 +and if you get an error, I just want nil, + +1114 +00:51:00,080 --> 00:51:01,750 +okay, just give me nil. + +1115 +00:51:01,750 --> 00:51:03,330 +Well, turns out we can do that. + +1116 +00:51:03,330 --> 00:51:06,040 +We can modify our Publisher +a little further here + +1117 +00:51:06,040 --> 00:51:10,800 +and say, replaceErrors +with some other UIImage, + +1118 +00:51:10,800 --> 00:51:13,390 +I'm gonna pick the UIImage nil. + +1119 +00:51:13,390 --> 00:51:17,880 +So now, this Publisher publishes UIImages, + +1120 +00:51:17,880 --> 00:51:19,550 +Optional UIImages still, + +1121 +00:51:19,550 --> 00:51:22,680 +but its error type has +been changed to Never. + +1122 +00:51:22,680 --> 00:51:25,480 +And now we could do sink and look, + +1123 +00:51:25,480 --> 00:51:27,313 +the receiveValue's available now. + +1124 +00:51:28,310 --> 00:51:30,220 +But I'm not even gonna use sink. + +1125 +00:51:30,220 --> 00:51:33,310 +So I'm gonna say let +canceller equal something + +1126 +00:51:33,310 --> 00:51:35,450 +but I'm not going to have it do sink, + +1127 +00:51:35,450 --> 00:51:38,530 +I'm going to have it do +a really cool Subscriber + +1128 +00:51:38,530 --> 00:51:40,610 +called assign. + +1129 +00:51:40,610 --> 00:51:43,860 +So assign lets you assign +the output of the Publisher + +1130 +00:51:43,860 --> 00:51:48,860 +to some var that you specify +using this key path syntax + +1131 +00:51:49,900 --> 00:51:51,370 +that we saw before + +1132 +00:51:54,000 --> 00:51:57,950 +on some object, in our case, our self. + +1133 +00:51:57,950 --> 00:52:00,170 +So this is gonna take whatever +this Publisher publishes + +1134 +00:52:00,170 --> 00:52:01,357 +and assign it to this var. + +1135 +00:52:01,357 --> 00:52:04,534 +And this will work as long +as this var, backgroundImage, + +1136 +00:52:04,534 --> 00:52:08,840 +has the same type, +UIImage, Optional UIImage, + +1137 +00:52:08,840 --> 00:52:10,430 +as what the Publisher is publishing. + +1138 +00:52:10,430 --> 00:52:13,460 +And that is exactly what +our Publisher publishes. + +1139 +00:52:13,460 --> 00:52:17,200 +Now assign only works if you +have Never as your error. + +1140 +00:52:17,200 --> 00:52:19,220 +So if you have something from Publisher + +1141 +00:52:19,220 --> 00:52:22,290 +that has an error, you're +gonna have to call replaceError + +1142 +00:52:22,290 --> 00:52:26,270 +and provide some value to +return from this Publisher + +1143 +00:52:26,270 --> 00:52:27,850 +if there is an error. + +1144 +00:52:27,850 --> 00:52:30,790 +In our case it's easy because +our UIImage is an Optional + +1145 +00:52:30,790 --> 00:52:32,520 +so we could return nil. + +1146 +00:52:32,520 --> 00:52:34,650 +But if you're publishing +something that's not an Optional + +1147 +00:52:34,650 --> 00:52:36,530 +you're gonna have to figure +out something reasonable + +1148 +00:52:36,530 --> 00:52:39,420 +to publish there if you +wanna have your failure type + +1149 +00:52:39,420 --> 00:52:41,593 +be Never by calling replaceError. + +1150 +00:52:43,390 --> 00:52:45,680 +And this EmojiArtDocument here, + +1151 +00:52:45,680 --> 00:52:48,210 +we can just let Swift +infer that from the fact + +1152 +00:52:48,210 --> 00:52:50,843 +that we know this key path is on self. + +1153 +00:52:51,970 --> 00:52:53,570 +This is just a Subscriber, + +1154 +00:52:53,570 --> 00:52:55,647 +that's why it has a canceller over here + +1155 +00:52:55,647 --> 00:52:57,730 +and of course we don't want this canceller + +1156 +00:52:57,730 --> 00:53:00,810 +to be a local variable +inside this function + +1157 +00:53:00,810 --> 00:53:02,870 +otherwise when this function ends, + +1158 +00:53:02,870 --> 00:53:06,280 +this assignment, this +Subscriber is goin' away. + +1159 +00:53:06,280 --> 00:53:08,150 +Exactly the same as we did up here + +1160 +00:53:08,150 --> 00:53:10,058 +when we had autosaveCancellable, + +1161 +00:53:10,058 --> 00:53:13,200 +we're gonna need to have some private var + +1162 +00:53:13,200 --> 00:53:16,257 +which I'm gonna call my +fetchImageCancellable, + +1163 +00:53:19,620 --> 00:53:21,070 +again, AnyCancellable is type + +1164 +00:53:23,346 --> 00:53:26,950 +and I'm gonna use this as the variable + +1165 +00:53:26,950 --> 00:53:31,000 +to put that Subscriber's cancellable into + +1166 +00:53:31,000 --> 00:53:32,430 +and that's gonna keep it around + +1167 +00:53:32,430 --> 00:53:35,140 +as long as this stays around. + +1168 +00:53:35,140 --> 00:53:37,200 +But don't forget that +this also has the benefit + +1169 +00:53:37,200 --> 00:53:39,070 +of letting me cancel this. + +1170 +00:53:39,070 --> 00:53:42,100 +And remember when we did +all the fetching ourselves + +1171 +00:53:42,100 --> 00:53:43,400 +we had to be careful + +1172 +00:53:43,400 --> 00:53:45,677 +that if someone clicked +on a background image + +1173 +00:53:45,677 --> 00:53:48,280 +and it was on a slow server +and it was taking too long + +1174 +00:53:48,280 --> 00:53:51,500 +and they dragged in a different +image from a fast server + +1175 +00:53:51,500 --> 00:53:54,080 +and that worked, and then 10 seconds later + +1176 +00:53:54,080 --> 00:53:57,250 +the slow server finally responded +and it blew out the image + +1177 +00:53:57,250 --> 00:53:58,900 +and we fixed that by having to check, + +1178 +00:53:58,900 --> 00:54:00,900 +oh, is this the image that just arrived + +1179 +00:54:00,900 --> 00:54:02,550 +the same one we're looking for? + +1180 +00:54:02,550 --> 00:54:04,800 +Well with this system we +don't have to do any of that + +1181 +00:54:04,800 --> 00:54:06,710 +'cause I'm just gonna say right here + +1182 +00:54:06,710 --> 00:54:08,340 +I'm only gonna do all this + +1183 +00:54:08,340 --> 00:54:11,660 +after I've taken my fetchImageCancellable + +1184 +00:54:11,660 --> 00:54:14,220 +and cancelled the previous one. + +1185 +00:54:14,220 --> 00:54:16,770 +This is also gonna keep us from +having outstanding requests + +1186 +00:54:16,770 --> 00:54:18,930 +that we're not interested in anymore. + +1187 +00:54:18,930 --> 00:54:21,580 +Every time we fetch the +background image data, + +1188 +00:54:21,580 --> 00:54:23,300 +I'm gonna cancel the previous one + +1189 +00:54:23,300 --> 00:54:24,270 +and go get the new one. + +1190 +00:54:24,270 --> 00:54:26,910 +So now I don't have to worry +about that thing changing + +1191 +00:54:26,910 --> 00:54:29,510 +'cause I'm only gonna be +ever fetching the new one. + +1192 +00:54:29,510 --> 00:54:32,980 +So it's a really cool +feature of Publishers as well + +1193 +00:54:32,980 --> 00:54:34,330 +is that you can cancel them + +1194 +00:54:34,330 --> 00:54:36,133 +and they'll stop doing their work. + +1195 +00:54:37,642 --> 00:54:39,640 +Now the only other thing we +would do with this code is + +1196 +00:54:39,640 --> 00:54:41,590 +we'd make this a one liner. + +1197 +00:54:41,590 --> 00:54:44,110 +So we would take this shared session + +1198 +00:54:44,110 --> 00:54:45,630 +and we would put it right here + +1199 +00:54:45,630 --> 00:54:48,290 +and we would take this whole Publisher + +1200 +00:54:48,290 --> 00:54:50,010 +and we would put it right here + +1201 +00:54:50,010 --> 00:54:53,193 +and we wouldn't have these +two intermediate variables. + +1202 +00:54:54,780 --> 00:54:59,060 +Pretty sweet, pretty simple, +pretty elegant solution + +1203 +00:54:59,060 --> 00:55:00,910 +to getting data. + +1204 +00:55:00,910 --> 00:55:03,950 +Just ask URLSession to go fetch it + +1205 +00:55:03,950 --> 00:55:05,610 +and it publishes the result, + +1206 +00:55:05,610 --> 00:55:07,190 +we massage into the format we want + +1207 +00:55:07,190 --> 00:55:10,333 +and then just assign it +to one of our variables. + +1208 +00:55:11,360 --> 00:55:14,300 +And with the backgroundImage +being set over here + +1209 +00:55:14,300 --> 00:55:16,850 +that's gonna cause this Publisher to fire + +1210 +00:55:16,850 --> 00:55:20,410 +which is over here gonna +cause this onReceive to notice + +1211 +00:55:20,410 --> 00:55:22,390 +and causes zoomToFit. + +1212 +00:55:22,390 --> 00:55:25,760 +So you're starting to see +this reactive UI thing, + +1213 +00:55:25,760 --> 00:55:28,210 +it starts all the way from like + +1214 +00:55:28,210 --> 00:55:29,540 +pulling things over the network + +1215 +00:55:29,540 --> 00:55:32,713 +and ripples all the way +through in a very natural way. + +1216 +00:55:33,980 --> 00:55:35,530 +We'll see this thing in action. + +1217 +00:55:38,740 --> 00:55:40,852 +Loading, woo, + +1218 +00:55:40,852 --> 00:55:42,487 +it worked, okay. + +1219 +00:55:42,487 --> 00:55:45,263 +How about, where's our other favorite one, + +1220 +00:55:46,988 --> 00:55:47,938 +could we load here. + +1221 +00:55:49,970 --> 00:55:50,803 +Here it is. + +1222 +00:55:52,250 --> 00:55:53,083 +Perfect. + +1223 +00:55:54,840 --> 00:55:56,550 +All right, that's it for +Publishers, you guys. + +1224 +00:55:56,550 --> 00:55:58,270 +We saw a lot going on +with Publishers there + +1225 +00:55:58,270 --> 00:56:00,653 +but we really only just +scratched the surface of it. + +1226 +00:56:00,653 --> 00:56:02,230 +There's a lot more to know + +1227 +00:56:02,230 --> 00:56:04,280 +and I will cover it later in the quarter. + +1228 +00:56:05,130 --> 00:56:07,090 +As always, you can go +look in the documentation + +1229 +00:56:07,090 --> 00:56:09,730 +for Publisher and see the +many many different functions + +1230 +00:56:09,730 --> 00:56:11,997 +you can call besides map and replaceError, + +1231 +00:56:11,997 --> 00:56:14,197 +and all these things, +just so much in there. + +1232 +00:56:15,270 --> 00:56:17,900 +But now we're gonna move +on to some UI stuff. + +1233 +00:56:17,900 --> 00:56:19,420 +I am going to make it so that we, + +1234 +00:56:19,420 --> 00:56:21,830 +instead of having just this one + +1235 +00:56:21,830 --> 00:56:23,993 +kinda sad little palette right here + +1236 +00:56:23,993 --> 00:56:25,470 +that we can have many palettes, + +1237 +00:56:25,470 --> 00:56:28,340 +a food palette, animals +palette, faces palette, + +1238 +00:56:28,340 --> 00:56:30,510 +so we can choose through +all kinds of emoji + +1239 +00:56:30,510 --> 00:56:33,100 +to build our beautiful artwork. + +1240 +00:56:33,100 --> 00:56:35,010 +So let's start by building +that little thing, + +1241 +00:56:35,010 --> 00:56:36,000 +this little chooser, + +1242 +00:56:36,000 --> 00:56:37,220 +it's just gonna be it's only little View + +1243 +00:56:37,220 --> 00:56:38,690 +so I'm gonna go back here + +1244 +00:56:39,690 --> 00:56:40,523 +file new + +1245 +00:56:41,960 --> 00:56:43,937 +it is gonna be a SwiftUIView + +1246 +00:56:45,229 --> 00:56:47,173 +I'm gonna call it PaletteChooser. + +1247 +00:56:49,780 --> 00:56:52,480 +And we all know how to make a View now, + +1248 +00:56:52,480 --> 00:56:54,300 +we just replace its body. + +1249 +00:56:54,300 --> 00:56:59,300 +Mine's gonna have an HStack +of something called a Stepper, + +1250 +00:56:59,310 --> 00:57:00,920 +which we're gonna talk about in a second, + +1251 +00:57:00,920 --> 00:57:05,070 +and then also just the +Text of the palette name + +1252 +00:57:05,070 --> 00:57:06,460 +which we're gonna have to get + +1253 +00:57:06,460 --> 00:57:07,940 +as we choose different palettes, + +1254 +00:57:07,940 --> 00:57:10,780 +this is going to be the +name of the palette, + +1255 +00:57:10,780 --> 00:57:12,390 +we want our palettes to have nice names + +1256 +00:57:12,390 --> 00:57:15,093 +like food, animals, faces, whatever. + +1257 +00:57:16,140 --> 00:57:17,300 +So what is this Stepper? + +1258 +00:57:17,300 --> 00:57:20,920 +The Stepper is essentially +like a little plus minus button + +1259 +00:57:20,920 --> 00:57:24,540 +and it might not be the real +perfect UI here for this + +1260 +00:57:24,540 --> 00:57:26,030 +but it's quite functional + +1261 +00:57:26,030 --> 00:57:27,820 +and it also lets me show you Stepper + +1262 +00:57:27,820 --> 00:57:29,110 +'cause I wanted to show it. + +1263 +00:57:29,110 --> 00:57:31,250 +So Stepper has a lot of +different initializers, + +1264 +00:57:31,250 --> 00:57:33,110 +you should check the documentation. + +1265 +00:57:33,110 --> 00:57:34,800 +For example, you can take a range + +1266 +00:57:34,800 --> 00:57:37,580 +and then you can step through the range. + +1267 +00:57:37,580 --> 00:57:40,970 +It also lets you just kinda +free form have a Stepper + +1268 +00:57:40,970 --> 00:57:43,970 +that just does, onIncrement +it does one thing + +1269 +00:57:43,970 --> 00:57:45,690 +and then onDecrement is does another. + +1270 +00:57:45,690 --> 00:57:47,450 +So we're gonna use that version. + +1271 +00:57:47,450 --> 00:57:49,670 +So onIncrement we'll specify some closure + +1272 +00:57:49,670 --> 00:57:52,550 +and onDecrement we'll specify some closure + +1273 +00:57:52,550 --> 00:57:54,800 +and Steppers have labels. + +1274 +00:57:54,800 --> 00:57:58,450 +I'm gonna have my label +here be a Text that says + +1275 +00:58:00,810 --> 00:58:05,110 +"Choose Palette", generally + +1276 +00:58:05,110 --> 00:58:10,110 +Stepper's labels tries to explain +what the Stepper is doing. + +1277 +00:58:10,510 --> 00:58:13,450 +I think it's going to be +pretty obvious in our app + +1278 +00:58:13,450 --> 00:58:15,230 +so it might be that we're gonna lose this, + +1279 +00:58:15,230 --> 00:58:18,360 +just get rid of this text, +but we'll see how it looks, + +1280 +00:58:18,360 --> 00:58:20,710 +'cause I want you to see +where the label appears + +1281 +00:58:20,710 --> 00:58:22,160 +on the Stepper. + +1282 +00:58:22,160 --> 00:58:25,100 +So before we start +implementing the actual Stepper + +1283 +00:58:25,100 --> 00:58:26,260 +stepping through our palettes, + +1284 +00:58:26,260 --> 00:58:28,330 +let's see what our View +looks like right here. + +1285 +00:58:28,330 --> 00:58:31,293 +So I'm gonna actually +bring out our canvas. + +1286 +00:58:33,590 --> 00:58:35,740 +Let's see if we can +take a look at it here. + +1287 +00:58:37,800 --> 00:58:39,840 +Ah, looks like we have a +little bit of a problem here. + +1288 +00:58:39,840 --> 00:58:42,292 +Let's hit diagnostics. + +1289 +00:58:42,292 --> 00:58:45,440 +Oh, I think I recognize this problem. + +1290 +00:58:45,440 --> 00:58:47,000 +This is the problem that many of you had + +1291 +00:58:47,000 --> 00:58:48,790 +in your assignment three. + +1292 +00:58:48,790 --> 00:58:50,950 +And your assignment +three write up explains + +1293 +00:58:50,950 --> 00:58:53,650 +how to work around this problem. + +1294 +00:58:53,650 --> 00:58:55,340 +What's going on here is +that Xcode is getting + +1295 +00:58:55,340 --> 00:58:58,343 +a little confused because +we have the name of a struct + +1296 +00:58:58,343 --> 00:59:01,060 +that is exactly the same +as the name of our app + +1297 +00:59:01,060 --> 00:59:04,503 +and Xcode doesn't quite +do the right thing here. + +1298 +00:59:04,503 --> 00:59:06,860 +This is probably even more of a problem + +1299 +00:59:06,860 --> 00:59:07,730 +for your assignment three + +1300 +00:59:07,730 --> 00:59:11,980 +since Swift itself has a struct named Set. + +1301 +00:59:11,980 --> 00:59:13,560 +So the two work arounds +for this are either + +1302 +00:59:13,560 --> 00:59:18,470 +to rename the offending +struct or to rename the app. + +1303 +00:59:18,470 --> 00:59:22,550 +So I'm gonna rename my app, +that's the simple thing to do. + +1304 +00:59:22,550 --> 00:59:24,710 +So I'm gonna go over here to my settings, + +1305 +00:59:24,710 --> 00:59:27,720 +pick my app under targets +and we'll change our name + +1306 +00:59:27,720 --> 00:59:31,460 +from EmojiArt to Emoji space Art, + +1307 +00:59:31,460 --> 00:59:34,930 +that might be a better name anyway. + +1308 +00:59:34,930 --> 00:59:37,623 +Let's go back and resume again. + +1309 +00:59:40,260 --> 00:59:43,640 +We can see our Stepper right here. + +1310 +00:59:43,640 --> 00:59:48,080 +And this is kind of in the +ballpark of what we want + +1311 +00:59:48,080 --> 00:59:50,140 +but not exactly what we want. + +1312 +00:59:50,140 --> 00:59:52,920 +This is the label of it, Choose Palette, + +1313 +00:59:52,920 --> 00:59:55,070 +and then this is the +plus minus, the Stepper, + +1314 +00:59:55,070 --> 00:59:58,520 +and this is the palette +name, so this part I like. + +1315 +00:59:58,520 --> 01:00:01,920 +But HStack is using all +the space available, + +1316 +01:00:01,920 --> 01:00:03,300 +the whole width right here + +1317 +01:00:03,300 --> 01:00:05,550 +and that's why it's so spread out. + +1318 +01:00:05,550 --> 01:00:08,260 +Well, we'll work on it +and we'll see how it goes. + +1319 +01:00:08,260 --> 01:00:10,710 +But it's kind of in the +ballpark of what I want + +1320 +01:00:10,710 --> 01:00:14,033 +so let's put this PaletteChooser +now in our main View. + +1321 +01:00:15,479 --> 01:00:18,130 +We're gonna put in an +HStack with our ScrollView, + +1322 +01:00:18,130 --> 01:00:20,580 +right, this is the ScrollView +that shows the palette. + +1323 +01:00:20,580 --> 01:00:25,580 +So let's make an HStack with +our PaletteChooser in there + +1324 +01:00:26,470 --> 01:00:30,333 +and then this ScrollView also in there. + +1325 +01:00:31,750 --> 01:00:32,623 +And we'll run. + +1326 +01:00:39,188 --> 01:00:41,550 +All right, well, we're +making some progress. + +1327 +01:00:41,550 --> 01:00:44,520 +This is kinda what I want, +this thing right here. + +1328 +01:00:44,520 --> 01:00:46,390 +But I definitely don't +want this ChoosePalette, + +1329 +01:00:46,390 --> 01:00:49,490 +it's really not necessary, +it's kind of obvious + +1330 +01:00:49,490 --> 01:00:51,740 +that this is going to be plus minus-ing + +1331 +01:00:51,740 --> 01:00:53,860 +whatever my palette name is here, + +1332 +01:00:53,860 --> 01:00:55,530 +food or animals or whatever. + +1333 +01:00:55,530 --> 01:00:58,283 +I'm definitely gonna +ditch that over there. + +1334 +01:01:00,430 --> 01:01:02,723 +Do that by making this be an empty field. + +1335 +01:01:07,160 --> 01:01:08,560 +So let's see how that looks. + +1336 +01:01:11,600 --> 01:01:13,630 +Hmmm, still not quite right. + +1337 +01:01:13,630 --> 01:01:16,180 +It looks like it's giving +me an equal amount of space + +1338 +01:01:16,180 --> 01:01:20,540 +to my palette View as it is +to the actual ScrollView. + +1339 +01:01:20,540 --> 01:01:24,410 +I really want this to not +get as much space as this. + +1340 +01:01:24,410 --> 01:01:25,880 +So we're gonna try something. + +1341 +01:01:25,880 --> 01:01:30,650 +Let's try doing, back in our main View, + +1342 +01:01:30,650 --> 01:01:33,983 +having the ScrollView get +a very high layoutPriority. + +1343 +01:01:36,090 --> 01:01:37,950 +Make your layoutPriority one, + +1344 +01:01:37,950 --> 01:01:41,440 +the default layoutPriority zero, + +1345 +01:01:41,440 --> 01:01:43,390 +so hopefully this will fix our problem. + +1346 +01:01:46,240 --> 01:01:48,270 +Uh, oops, mmm. + +1347 +01:01:48,270 --> 01:01:50,010 +Well, this is interesting. + +1348 +01:01:50,010 --> 01:01:52,810 +It definitely gave a lot +more space to our ScrollView + +1349 +01:01:52,810 --> 01:01:57,150 +but it didn't give enough space +now to our PaletteChooser, + +1350 +01:01:57,150 --> 01:02:00,380 +just kinda smash it over +here and not enough space. + +1351 +01:02:00,380 --> 01:02:02,710 +So this is really not the right solution, + +1352 +01:02:02,710 --> 01:02:04,780 +it's close but it's +not the right solution. + +1353 +01:02:04,780 --> 01:02:06,700 +The real way we wanna do this + +1354 +01:02:06,700 --> 01:02:10,850 +is to have our PaletteChooser +over here fix its size. + +1355 +01:02:10,850 --> 01:02:12,480 +So we want it to be fixedSize + +1356 +01:02:12,480 --> 01:02:15,320 +in the horizontal direction, true, + +1357 +01:02:15,320 --> 01:02:17,700 +vertically we don't care, false + +1358 +01:02:17,700 --> 01:02:20,860 +and fixedSize means that it's going to + +1359 +01:02:20,860 --> 01:02:22,860 +kind of size itself to fit + +1360 +01:02:22,860 --> 01:02:27,367 +and not going to use any extra +space that's offered to it. + +1361 +01:02:27,367 --> 01:02:29,203 +And we'll see what this looks like. + +1362 +01:02:30,720 --> 01:02:32,430 +Oh, it looks much much better. + +1363 +01:02:32,430 --> 01:02:34,320 +And we've got, ditched the title + +1364 +01:02:34,320 --> 01:02:38,580 +and now it's kinda, instead +of using all this space + +1365 +01:02:38,580 --> 01:02:41,727 +it's setting itself up +in the middle right here + +1366 +01:02:41,727 --> 01:02:44,370 +and I have a feeling +that's gonna look good + +1367 +01:02:44,370 --> 01:02:47,340 +in our UI here as well + +1368 +01:02:47,340 --> 01:02:49,322 +and indeed it does. + +1369 +01:02:49,322 --> 01:02:51,050 +And it doesn't look like +I need quite so much + +1370 +01:02:51,050 --> 01:02:55,117 +horizontal padding now, this +Stepper has, you can see, + +1371 +01:02:55,117 --> 01:02:57,620 +has it's own little padding around it + +1372 +01:02:57,620 --> 01:03:01,110 +so that horizontal padding +that we had done over here + +1373 +01:03:01,110 --> 01:03:03,343 +probably completely unnecessary. + +1374 +01:03:06,010 --> 01:03:07,960 +All right, I'm likin' the look of this. + +1375 +01:03:09,686 --> 01:03:10,850 +And what I want is that when I press + +1376 +01:03:10,850 --> 01:03:12,520 +these plus and minus buttons, + +1377 +01:03:12,520 --> 01:03:15,660 +it cycles through all +the palettes that I have, + +1378 +01:03:15,660 --> 01:03:20,220 +food, faces, animals, +whatever palettes that I have + +1379 +01:03:20,220 --> 01:03:23,280 +or that I've created, I want +it to cycle through them. + +1380 +01:03:23,280 --> 01:03:24,620 +So how am I gonna do that? + +1381 +01:03:24,620 --> 01:03:28,740 +Well, I don't want to waste +too much of our time in demo + +1382 +01:03:28,740 --> 01:03:31,900 +how do we get an Array of palettes + +1383 +01:03:31,900 --> 01:03:33,980 +and step through them and all that. + +1384 +01:03:33,980 --> 01:03:37,910 +So I actually did that offline, +this little code right here, + +1385 +01:03:37,910 --> 01:03:40,620 +which you all have from the forums + +1386 +01:03:40,620 --> 01:03:43,290 +was posted before this lecture, + +1387 +01:03:43,290 --> 01:03:45,640 +and we're not gonna go through all this, + +1388 +01:03:45,640 --> 01:03:48,460 +but it has some default palettes in here + +1389 +01:03:48,460 --> 01:03:51,790 +and it lets you add and +remove emoji from a palette + +1390 +01:03:51,790 --> 01:03:55,440 +and it has these really two +very good function for Steppers + +1391 +01:03:55,440 --> 01:03:58,240 +which is give me the palette +after some other palette + +1392 +01:03:58,240 --> 01:04:00,940 +and give me the palette +before some other palette. + +1393 +01:04:00,940 --> 01:04:03,100 +So I'm gonna use those to do my Stepper, + +1394 +01:04:03,100 --> 01:04:04,253 +before and after. + +1395 +01:04:06,260 --> 01:04:07,800 +So inside my PaletteChooser, + +1396 +01:04:07,800 --> 01:04:10,860 +I need some state of the +palette that I've chosen. + +1397 +01:04:10,860 --> 01:04:13,760 +So I'm gonna add an @State var here. + +1398 +01:04:13,760 --> 01:04:17,300 +By the way, State vars should +almost always be private. + +1399 +01:04:17,300 --> 01:04:18,610 +If they can be private they should. + +1400 +01:04:18,610 --> 01:04:20,690 +The only time it might not be private + +1401 +01:04:20,690 --> 01:04:22,920 +is if you're letting +someone initialize them + +1402 +01:04:22,920 --> 01:04:24,850 +when they create your +thing, but, you know, + +1403 +01:04:24,850 --> 01:04:27,910 +this state, in an @State, +is private to your View, + +1404 +01:04:27,910 --> 01:04:30,520 +can only be really looked +at, seen by your View. + +1405 +01:04:30,520 --> 01:04:32,573 +So we almost always mark those private. + +1406 +01:04:33,740 --> 01:04:35,513 +I'm gonna call this chosenPalette, + +1407 +01:04:35,513 --> 01:04:37,900 +it's gonna be the +chosenPalette, which is a String + +1408 +01:04:37,900 --> 01:04:41,610 +and we'll start it out +just being nothing here. + +1409 +01:04:41,610 --> 01:04:44,840 +And then I'm gonna have my +Stepper just when I hit plus, + +1410 +01:04:44,840 --> 01:04:46,815 +it's gonna go to the +palette after this one + +1411 +01:04:46,815 --> 01:04:49,338 +and when I hit minus, it's +gonna go to the one before. + +1412 +01:04:49,338 --> 01:04:54,338 +It's easy, self.chosenPalette +equals my document + +1413 +01:04:55,690 --> 01:04:58,110 +so I need my document here. + +1414 +01:04:58,110 --> 01:04:59,970 +Somehow I need my document +so that I can say, + +1415 +01:04:59,970 --> 01:05:04,970 +palette after my current +self.chosenPalette. + +1416 +01:05:08,960 --> 01:05:11,140 +So I need my document, so +let's go and put that up here. + +1417 +01:05:11,140 --> 01:05:12,212 +We can do that. + +1418 +01:05:12,212 --> 01:05:17,212 +ObservedObject var document +which is an EmojiArtDocument. + +1419 +01:05:18,270 --> 01:05:19,560 +It does mean, however, + +1420 +01:05:19,560 --> 01:05:22,300 +that when we create our +paletteChooser over here, + +1421 +01:05:22,300 --> 01:05:23,133 +see paletteChooser, + +1422 +01:05:23,133 --> 01:05:25,543 +we're gonna have to +pass the document along. + +1423 +01:05:28,990 --> 01:05:30,870 +Pass our document up here + +1424 +01:05:30,870 --> 01:05:33,790 +into our paletteChooser which +is fine, we can do that. + +1425 +01:05:33,790 --> 01:05:36,230 +We'll see a different +way to do that next time, + +1426 +01:05:36,230 --> 01:05:37,380 +but it'll work for now. + +1427 +01:05:38,320 --> 01:05:40,390 +And then, when we +decrement, we're gonna say + +1428 +01:05:40,390 --> 01:05:45,390 +self.chosenPalette = +self.document.palette before. + +1429 +01:05:48,127 --> 01:05:49,680 +So it lets us increment and decrement 'em. + +1430 +01:05:49,680 --> 01:05:51,780 +The other thing is we don't +wanna say "Palette Name" here, + +1431 +01:05:51,780 --> 01:05:53,350 +we actually want the name of the palette. + +1432 +01:05:53,350 --> 01:05:55,897 +I have a nice little dictionary for that + +1433 +01:05:55,897 --> 01:05:57,380 +and say the text here is + +1434 +01:05:57,380 --> 01:05:59,400 +document.paletteNames chosenPalette + +1435 +01:06:03,270 --> 01:06:04,500 +and if I can't find it, + +1436 +01:06:04,500 --> 01:06:07,853 +I'm just going to have an empty name. + +1437 +01:06:09,290 --> 01:06:10,510 +PaletteChooser down here, + +1438 +01:06:10,510 --> 01:06:12,860 +let's just create an +empty document for it, + +1439 +01:06:12,860 --> 01:06:16,823 +EmojiArtDocument and run. + +1440 +01:06:18,588 --> 01:06:19,520 +Here we go. + +1441 +01:06:19,520 --> 01:06:21,470 +It starts out with a palette of nothing + +1442 +01:06:21,470 --> 01:06:23,270 +but if I start cycling through, woo, + +1443 +01:06:24,210 --> 01:06:26,910 +look at that, activities, +animals, faces, food. + +1444 +01:06:26,910 --> 01:06:28,133 +Now, the interesting thing is, + +1445 +01:06:28,133 --> 01:06:32,040 +that it's definitely cycling +through my available palettes + +1446 +01:06:32,040 --> 01:06:34,080 +which you can see over here, + +1447 +01:06:34,080 --> 01:06:35,900 +faces, food, animals, activities, + +1448 +01:06:35,900 --> 01:06:40,240 +but it's not changing the +palettes to actually be that. + +1449 +01:06:40,240 --> 01:06:41,560 +This palette is staying this kind + +1450 +01:06:41,560 --> 01:06:44,050 +of sad little palette here. + +1451 +01:06:44,050 --> 01:06:47,050 +Well, that makes perfect sense +because our PaletteChooser + +1452 +01:06:47,050 --> 01:06:50,620 +is just choosing it inside +local State in this View, + +1453 +01:06:50,620 --> 01:06:52,960 +it's not choosing it anywhere else, + +1454 +01:06:52,960 --> 01:06:55,710 +it's just setting this little +chosenPalette right here. + +1455 +01:06:57,280 --> 01:06:59,760 +By the way, I could probably +also fix this problem + +1456 +01:06:59,760 --> 01:07:02,260 +where it comes up with no palette + +1457 +01:07:02,260 --> 01:07:03,593 +by doing something like, + +1458 +01:07:06,785 --> 01:07:09,952 +onAppear, in that say my chosenPalette + +1459 +01:07:12,260 --> 01:07:16,033 +equals my document's default palette. + +1460 +01:07:16,970 --> 01:07:20,260 +And I'm doing this onAppear +rather than trying to do this, + +1461 +01:07:20,260 --> 01:07:22,253 +for example, up here. + +1462 +01:07:23,680 --> 01:07:25,130 +Can't do it up here + +1463 +01:07:25,130 --> 01:07:27,710 +because here we're in the +initialization process + +1464 +01:07:27,710 --> 01:07:31,280 +and this var has not been initialized yet. + +1465 +01:07:31,280 --> 01:07:33,824 +So, whenever you find yourself saying, oh, + +1466 +01:07:33,824 --> 01:07:38,770 +I want to initialize some +state from some other var + +1467 +01:07:38,770 --> 01:07:41,090 +from my ObservedObject, no problem. + +1468 +01:07:41,090 --> 01:07:44,310 +Just hold on and set it +to zero or something, nil, + +1469 +01:07:44,310 --> 01:07:47,513 +empty String, and then +onAppear you can do it. + +1470 +01:07:51,020 --> 01:07:52,280 +Voila. + +1471 +01:07:52,280 --> 01:07:55,330 +So we fixed our problem +where we weren't having + +1472 +01:07:55,330 --> 01:07:57,327 +an initial palette shown there. + +1473 +01:07:57,327 --> 01:08:00,930 +And our PaletteChooser, +pretty much ready to go here. + +1474 +01:08:00,930 --> 01:08:04,440 +However, we're really not doing +anything with our palettes + +1475 +01:08:04,440 --> 01:08:07,620 +in our main scrollable palette over here. + +1476 +01:08:07,620 --> 01:08:09,300 +So we need to get that thing + +1477 +01:08:09,300 --> 01:08:11,153 +to start showing the chosenPalette. + +1478 +01:08:12,520 --> 01:08:13,860 +So let's start by at least getting it + +1479 +01:08:13,860 --> 01:08:15,650 +to show the default palette. + +1480 +01:08:15,650 --> 01:08:18,690 +And we're gonna do that by +creating some state over here + +1481 +01:08:18,690 --> 01:08:23,270 +in our main View, @State +var chosenPalette, + +1482 +01:08:24,860 --> 01:08:27,070 +String equals nothing. + +1483 +01:08:27,070 --> 01:08:29,430 +I'll even do the same trick over here + +1484 +01:08:29,430 --> 01:08:32,410 +onAppear, I'm copying and pasting code, + +1485 +01:08:32,410 --> 01:08:35,340 +that's probably going to be a problem, + +1486 +01:08:35,340 --> 01:08:38,010 +but we'll see that that +problem is not going to matter + +1487 +01:08:38,010 --> 01:08:39,620 +in just mere moments. + +1488 +01:08:39,620 --> 01:08:42,110 +And now instead of saying +the EmojiArt palette, + +1489 +01:08:42,110 --> 01:08:45,040 +I'm gonna say my chosenPalette + +1490 +01:08:45,040 --> 01:08:47,703 +and use my chosenPalette instead. + +1491 +01:08:49,357 --> 01:08:50,707 +And that's all I need to do + +1492 +01:08:52,300 --> 01:08:55,420 +to start using, woohoo, +the default palette + +1493 +01:08:55,420 --> 01:08:56,650 +and look, it even lines up, + +1494 +01:08:56,650 --> 01:08:58,090 +'cause this is using the default palette. + +1495 +01:08:58,090 --> 01:08:59,080 +Oh, let's go to the next one. + +1496 +01:08:59,080 --> 01:09:01,990 +Uh oh, food, that's not food. + +1497 +01:09:01,990 --> 01:09:04,200 +Oh, it's not working. + +1498 +01:09:04,200 --> 01:09:05,320 +So what's going on here? + +1499 +01:09:05,320 --> 01:09:08,340 +Why is this chosenPalette +changing and this one's not? + +1500 +01:09:08,340 --> 01:09:11,760 +Well it's because this +chosenPalette is in one State var + +1501 +01:09:11,760 --> 01:09:14,860 +in this View and this chosenPalette + +1502 +01:09:14,860 --> 01:09:16,960 +is in a different State +var in another View. + +1503 +01:09:16,960 --> 01:09:18,670 +So these things have +nothing to do with it. + +1504 +01:09:18,670 --> 01:09:20,960 +The only thing that's +the same is their name. + +1505 +01:09:20,960 --> 01:09:22,930 +But they're totally different State. + +1506 +01:09:22,930 --> 01:09:27,067 +But clearly we want these +two things to be the same. + +1507 +01:09:27,067 --> 01:09:29,510 +And we do this with a Binding. + +1508 +01:09:29,510 --> 01:09:32,040 +So instead of having its own state here + +1509 +01:09:32,040 --> 01:09:33,090 +in the paletteChooser, + +1510 +01:09:33,090 --> 01:09:35,990 +it's just going to have a Binding. + +1511 +01:09:35,990 --> 01:09:38,090 +And Bindings are usually not private + +1512 +01:09:38,090 --> 01:09:42,070 +because we're gonna be setting +them from outside somehow + +1513 +01:09:42,070 --> 01:09:44,230 +and also Bindings, we +don't initialize them + +1514 +01:09:44,230 --> 01:09:46,460 +because a Binding means that this var + +1515 +01:09:46,460 --> 01:09:48,110 +is gonna get and set its value + +1516 +01:09:48,110 --> 01:09:50,290 +from some other var somewhere else. + +1517 +01:09:50,290 --> 01:09:52,740 +So presumably that some +other var somewhere else + +1518 +01:09:52,740 --> 01:09:54,940 +is the thing that's +going to be initialized. + +1519 +01:09:58,360 --> 01:10:00,530 +All right, so how do we set up the Binding + +1520 +01:10:00,530 --> 01:10:05,160 +between this chosenPalette +and this chosenPalette? + +1521 +01:10:05,160 --> 01:10:08,350 +Well, we just pass it, +very simple, we just say, + +1522 +01:10:08,350 --> 01:10:13,120 +chosenPalette, because +chosenPalette is just a var, + +1523 +01:10:13,120 --> 01:10:15,487 +nothing more than a var in PaletteChooser + +1524 +01:10:15,487 --> 01:10:17,670 +and we're creating a +PaletteChooser over there + +1525 +01:10:17,670 --> 01:10:20,340 +so we can set any unset vars, + +1526 +01:10:20,340 --> 01:10:24,460 +we're setting this unset var +and we can set this one as well + +1527 +01:10:24,460 --> 01:10:28,260 +and what we set it to, +though, is the projectedValue + +1528 +01:10:28,260 --> 01:10:30,560 +of our chosenPalette. + +1529 +01:10:30,560 --> 01:10:34,350 +So this State, remember, +it has a $ as well, + +1530 +01:10:34,350 --> 01:10:37,307 +but it's not a Publisher, +that's the $ of @Published. + +1531 +01:10:38,484 --> 01:10:43,467 +The $ of an @State is a +Binding to this chosenPalette. + +1532 +01:10:44,480 --> 01:10:49,030 +So that's why I can pass +it here, $chosenPalette, + +1533 +01:10:49,030 --> 01:10:52,970 +matches the type of this +var, which is a Binding, + +1534 +01:10:52,970 --> 01:10:53,923 +to this String. + +1535 +01:10:55,340 --> 01:10:58,180 +Now, because I'm Binding +these two things together, + +1536 +01:10:58,180 --> 01:11:00,890 +this thing and this, I +don't need to do onAppear + +1537 +01:11:00,890 --> 01:11:03,030 +in one or other of them, + +1538 +01:11:03,030 --> 01:11:05,830 +so let's just not do the onAppear here. + +1539 +01:11:05,830 --> 01:11:07,890 +The onAppear is gonna happen over here, + +1540 +01:11:07,890 --> 01:11:10,040 +it's gonna set that and +that's gonna communicate + +1541 +01:11:10,040 --> 01:11:12,360 +through the Binding to this guy, + +1542 +01:11:12,360 --> 01:11:13,820 +and he's gonna see the same thing. + +1543 +01:11:13,820 --> 01:11:16,530 +And same, when he chooses +increment or decrement, + +1544 +01:11:16,530 --> 01:11:19,110 +it's going to communicate +back through the Binding + +1545 +01:11:19,110 --> 01:11:20,760 +the other way. + +1546 +01:11:20,760 --> 01:11:22,940 +Now before we can run, we +have to fix our preview + +1547 +01:11:22,940 --> 01:11:27,750 +because our preview needs +a chosenPalette argument + +1548 +01:11:27,750 --> 01:11:29,270 +because it's creating it. + +1549 +01:11:29,270 --> 01:11:32,030 +What does a preview pass? + +1550 +01:11:32,030 --> 01:11:34,140 +There are actually ways to make a preview + +1551 +01:11:34,140 --> 01:11:37,040 +have a live Binding but +it's way beyond the scope + +1552 +01:11:37,040 --> 01:11:38,290 +of what we're doing here. + +1553 +01:11:38,290 --> 01:11:42,700 +So I'm gonna pass a .constant Binding + +1554 +01:11:42,700 --> 01:11:45,010 +and I'm gonna have that Binding +be, doesn't really matter, + +1555 +01:11:45,010 --> 01:11:48,630 +can be any String, so this +chosenPalette in my preview + +1556 +01:11:48,630 --> 01:11:51,750 +is gonna be bound to the +palette nothingness there, + +1557 +01:11:51,750 --> 01:11:53,350 +empty String. + +1558 +01:11:53,350 --> 01:11:55,100 +Clicking the plus minus +is not gonna do anything + +1559 +01:11:55,100 --> 01:11:56,083 +in my preview. + +1560 +01:11:57,890 --> 01:11:59,343 +All right, take a look. + +1561 +01:12:02,400 --> 01:12:03,630 +Good, they're synced up. + +1562 +01:12:03,630 --> 01:12:05,570 +This looks like animals, this is animals, + +1563 +01:12:05,570 --> 01:12:10,570 +how about plus, woo, faces, +food, activities, animals. + +1564 +01:12:12,360 --> 01:12:16,700 +So this kind of Binding where +we're Binding two Views' State + +1565 +01:12:16,700 --> 01:12:19,490 +really crucial in SwiftUI. + +1566 +01:12:19,490 --> 01:12:21,170 +I'm amazed we got all the way + +1567 +01:12:21,170 --> 01:12:22,950 +through four weeks of this course + +1568 +01:12:22,950 --> 01:12:26,020 +and we manage to avoid +talking about Bindings, + +1569 +01:12:26,020 --> 01:12:27,080 +really important. + +1570 +01:12:27,080 --> 01:12:30,530 +And not just Binding between +two of our own Views, + +1571 +01:12:30,530 --> 01:12:35,530 +okay, our EmojiArtFocument View +and our PaletteChooser View + +1572 +01:12:35,580 --> 01:12:40,580 +but Binding between our +Views and SwiftUI's Views, + +1573 +01:12:40,600 --> 01:12:42,570 +especially things like TextFields, + +1574 +01:12:42,570 --> 01:12:44,610 +that's how we get the +text out of the TextField + +1575 +01:12:44,610 --> 01:12:45,620 +that someone is typing in, + +1576 +01:12:45,620 --> 01:12:48,410 +or toggles where we're +toggling something on or off, + +1577 +01:12:48,410 --> 01:12:51,600 +we'll have a Binding to +a Bool when we do that. + +1578 +01:12:51,600 --> 01:12:54,960 +Even things like I'm going +to put another View on screen + +1579 +01:12:54,960 --> 01:12:57,390 +in a way that kinda takes over the screen, + +1580 +01:12:57,390 --> 01:13:00,120 +and when it's done it's gonna let me know + +1581 +01:13:00,120 --> 01:13:01,970 +through a Binding. + +1582 +01:13:01,970 --> 01:13:05,350 +After a boolean Binding +says yeah, I'm done or not. + +1583 +01:13:05,350 --> 01:13:07,920 +So we're gonna see all that +in the next few lectures. + +1584 +01:13:07,920 --> 01:13:12,240 +A lot of use of this Binding, +so get used to seeing it. + +1585 +01:13:12,240 --> 01:13:13,460 +And that's it for today, + +1586 +01:13:13,460 --> 01:13:15,363 +so we'll pick up with this next time. + +1587 +01:13:16,620 --> 01:13:19,873 +- [Narrator] For more, please +visit us at Stanford.edu.