0 1 00:00:00,930 --> 00:00:06,680 In the last lesson, we learned about the observe a pattern and how we can use it for state management. 1 2 00:00:06,690 --> 00:00:11,880 We also saw how we can use the onAppear method to trigger our networking code. 2 3 00:00:11,880 --> 00:00:16,310 So at this point, we need to figure out how to display a web site in our app 3 4 00:00:16,470 --> 00:00:19,220 when a user clicks on one of the list items. 4 5 00:00:19,250 --> 00:00:20,850 So how do we go about doing that? 5 6 00:00:20,850 --> 00:00:23,770 How do we display the details of a list item? 6 7 00:00:24,870 --> 00:00:28,200 Well, in that case, we would need another view. 7 8 00:00:28,200 --> 00:00:35,040 So let's go ahead and put our ContentView into a New Group from Selection and we'll call these our 8 9 00:00:35,130 --> 00:00:36,660 Views. 9 10 00:00:36,990 --> 00:00:45,330 And in addition to the Content View, I'm gonna create a New File and I'm gonna create a SwiftUI View 10 11 00:00:45,390 --> 00:00:53,130 file this time. I'm going to call it our DetailView because that's the detail that will show up when 11 12 00:00:53,130 --> 00:01:00,780 we click on one of the cells in our list. And inside this DetailView, the most important thing that may 12 13 00:01:00,810 --> 00:01:08,130 be passed over is going to be the url as a string. But, of course, because the URL can be 13 14 00:01:08,130 --> 00:01:08,700 nil, 14 15 00:01:08,700 --> 00:01:16,170 I'm gonna set this as an optional string. And because we now have this property that needs to be initialized 15 16 00:01:16,680 --> 00:01:22,030 in our preview, we also have to provide a value for URL property, 16 17 00:01:22,080 --> 00:01:31,050 so I'm just gonna put "https://www.google.com," and then close off the string 17 18 00:01:31,050 --> 00:01:37,830 right there, then I'm gonna select this "Hello World!" placeholder, hit enter for it to be solidified into 18 19 00:01:37,890 --> 00:01:46,200 our text. And now if we resume updating, you should see that the DetailView is just going to be a pretty 19 20 00:01:46,200 --> 00:01:53,700 blank view. And all it does is just show the words "Hello World!" But the important thing is how do we get 20 21 00:01:53,700 --> 00:02:01,940 to the DetailView? So to do that, I'm going to navigate there from my ContentView. And the idea here is that 21 22 00:02:02,000 --> 00:02:10,400 whenever a user clicks on one of these items in the list on their titles, it should take them to the 22 23 00:02:10,400 --> 00:02:14,700 DetailView. So how do we create this behavior? 23 24 00:02:15,250 --> 00:02:23,950 Well, in order to do that, I'm going to use something called a NavigationLink. And this Navigation Link 24 25 00:02:24,040 --> 00:02:31,690 is going to create a button on the right-hand side of each cell and it's going to trigger a presentation 25 26 00:02:31,930 --> 00:02:39,520 to the DetailView when it's pressed. And we're going to initialize our navigation link using this particular 26 27 00:02:39,520 --> 00:02:40,330 initializer. 27 28 00:02:41,020 --> 00:02:43,320 So we're going to create a destination. 28 29 00:02:43,330 --> 00:02:50,290 So what are we going to show on screen with the transition when the user clicks on this link, and then 29 30 00:02:50,290 --> 00:02:56,320 we have to create a label which is what are we going to show inside this link. So you can imagine each 30 31 00:02:56,320 --> 00:03:03,160 NavigationLink now is going to be a cell. And what used to be in the contents of our cell is now going 31 32 00:03:03,160 --> 00:03:05,750 to be the label of our NavigationLink. 32 33 00:03:05,830 --> 00:03:14,080 So let's hit enter on this one. And the destination is going to be a DetailView that we created just 33 34 00:03:14,080 --> 00:03:15,010 now. 34 35 00:03:15,010 --> 00:03:19,450 And, of course, DetailView need to be initialized with a URL. 35 36 00:03:19,570 --> 00:03:23,340 So it's going to be the URL that we get from our 36 37 00:03:23,410 --> 00:03:32,470 post.url, the one from our API request. And then in our label, we're going to add a closure. 37 38 00:03:32,470 --> 00:03:35,260 So we're going to hit enter on that template code, 38 39 00:03:35,260 --> 00:03:43,900 delete this placeholder, and then move what used to be inside our list cell into our NavigationLink, 39 40 00:03:44,380 --> 00:03:51,490 and then I'm going to select command A and control I to reindent our code, so that we can see it a little 40 41 00:03:51,490 --> 00:03:56,070 bit better. And then I'm gonna go ahead and run my app. 41 42 00:03:59,280 --> 00:04:06,150 So, now you can see that when I list gets rendered, each of them come with a little disclosure indicator 42 43 00:04:06,150 --> 00:04:06,710 on the right, 43 44 00:04:07,290 --> 00:04:14,490 so it tells the user that this is clickable. And when I click on this, it should probably take us to discover 44 45 00:04:14,490 --> 00:04:16,950 more about this particular posts. 45 46 00:04:17,160 --> 00:04:21,560 And when I click on it, it indeed does take us to our DetailView. 46 47 00:04:21,930 --> 00:04:27,930 So we've now got a two-screen app with a ListView and the DetailView 47 48 00:04:27,930 --> 00:04:35,430 and we now have to turn this DetailView into a web view that shows the actual news piece based on 48 49 00:04:35,430 --> 00:04:42,190 that URL that were passing over. So let's go over to the DetailView and try to achieve this. 49 50 00:04:43,860 --> 00:04:52,380 Now, in order to display a URL inside effectively a browser without the search bar and the other parts 50 51 00:04:52,380 --> 00:04:54,240 that make a browser a browser, 51 52 00:04:54,240 --> 00:04:59,270 in fact, just a window basically that shows the content of a URL, 52 53 00:04:59,490 --> 00:05:02,020 we need to use something called a web view. 53 54 00:05:02,250 --> 00:05:08,820 But unfortunately, there is no such thing as a web view for SwiftUI at least at the time of recording. 54 55 00:05:08,820 --> 00:05:14,380 So instead, we have to go to UIKit land and borrow some of the big boy tools over there. 55 56 00:05:14,910 --> 00:05:20,360 So to do that, I'm going to create a new struct called a WebView. 56 57 00:05:20,580 --> 00:05:28,860 And in this struct, I'm going to try and construct a SwiftUI version of a UIKit component which is 57 58 00:05:28,860 --> 00:05:40,020 the WK WebView. And in order to use the WebView, we first have to remember to import the WebKit. 58 59 00:05:40,040 --> 00:05:48,020 So, now I can create my struct called WebView and it's going to conform to the protocol which is 59 60 00:05:48,110 --> 00:05:50,480 UIViewRepresentable. 60 61 00:05:50,540 --> 00:05:57,170 And this allows us to create a SwiftUIView that represents a UIKitView. 61 62 00:05:57,170 --> 00:06:01,970 So let's hit enter on that and create it. 62 63 00:06:02,170 --> 00:06:08,950 And now you can see this WebView doesn't conform to the protocol. In order to silence these warnings, 63 64 00:06:08,980 --> 00:06:12,730 we have to create two delegate methods in here. 64 65 00:06:12,730 --> 00:06:16,300 One is called makeUIView. 65 66 00:06:16,450 --> 00:06:27,960 And another is called updateUIView. So when we make this UIView, it's going to try and create a 66 67 00:06:27,960 --> 00:06:32,910 UIKit WebView and turn it into a SwiftUI View. 67 68 00:06:33,450 --> 00:06:35,860 So the view that we want to make, 68 69 00:06:35,880 --> 00:06:44,550 so what we want to return is going to be a WK Web Kit WebView, and then we're going to add the parentheses 69 70 00:06:44,550 --> 00:06:51,960 at the end to initialize it. And in order to update the UIView or what should we display in it, 70 71 00:06:51,990 --> 00:06:58,830 we're going to use the URL that got passed into the DetailView and try to render a WebKit view 71 72 00:06:58,860 --> 00:07:01,520 that uses that URL. 72 73 00:07:01,650 --> 00:07:09,620 So let's add a property to this struct code urlString which is going to be an optional string. 73 74 00:07:10,560 --> 00:07:17,100 And then in the body of our DetailView, instead of creating the "Hello World!" text, we're going to create 74 75 00:07:17,130 --> 00:07:23,880 this web view, and we're going to initialize it with that URL string which is the URL that 75 76 00:07:23,880 --> 00:07:27,850 we got passed over into the DetailView here. 76 77 00:07:27,870 --> 00:07:35,700 So, now we can focus on our WebView. And in our WebView when we need to update it, we're going to first 77 78 00:07:35,700 --> 00:07:39,880 check to see the URL string actually has some content. 78 79 00:07:39,960 --> 00:07:44,370 So let's call it safeString to make it easy to see what's going on. 79 80 00:07:44,370 --> 00:07:52,500 I'm going to set that to equal the urlString. And if that is not nil, then we're going to say, 80 81 00:07:52,560 --> 00:08:00,740 "if let url = URL from string, and we're going to use that safeString that we unwrapped 81 82 00:08:00,780 --> 00:08:11,710 just now. Now, finally, we can create a request from this URL which is a URLRequest and we're going 82 83 00:08:11,710 --> 00:08:20,630 to pass in the URL as the safeURL that we just created just now. And then the final thing, we have 83 84 00:08:20,630 --> 00:08:29,980 to do is use the UIView that we made up here, and then use one of its method which is called load, 84 85 00:08:30,500 --> 00:08:35,170 and it should load our request. 85 86 00:08:35,210 --> 00:08:36,980 Now, we're getting a few errors here. 86 87 00:08:37,340 --> 00:08:44,660 And the first thing that we have to fix is the data type of the UIView that we've made over here which 87 88 00:08:44,660 --> 00:08:48,620 we know is actually not a WebView. 88 89 00:08:48,620 --> 00:08:52,650 It's actually a WKWebView. 89 90 00:08:52,730 --> 00:08:59,240 Now, in addition to that, we can actually simplify our code a little bit. Instead of using this really 90 91 00:08:59,240 --> 00:09:05,240 long and complex UIViewRepesentableContext that is of type WebView, 91 92 00:09:05,330 --> 00:09:11,560 we can actually use a type alias which is just called Context which you can see is basically the same thing. 92 93 00:09:11,570 --> 00:09:14,830 It's just the same type as what we had before. 93 94 00:09:14,840 --> 00:09:20,510 So let's replace both of these places with Context to clean up our code. 94 95 00:09:20,510 --> 00:09:28,580 And now what should happen is when the DetailView loads up, it gets passed a URL string which gets 95 96 00:09:28,580 --> 00:09:35,510 used to create a WebView from a UIKit component which is called WKWebView. 96 97 00:09:35,510 --> 00:09:40,770 Once that gets created, then we update it by loading 97 98 00:09:40,790 --> 00:09:45,050 the URL that is meant to show in our DetailView. 98 99 00:09:45,050 --> 00:09:46,340 So that's the theory. 99 100 00:09:46,340 --> 00:09:48,290 Let's go ahead and run it and see if it works. 100 101 00:09:51,090 --> 00:09:52,400 As soon as we load up our app, 101 102 00:09:52,410 --> 00:10:00,840 we get all of our posts, and then if I select one of these posts, it goes to my DetailView and it loads 102 103 00:10:00,840 --> 00:10:08,160 up a UIKit WKWebView showing me the actual article that I've selected. 103 104 00:10:08,160 --> 00:10:15,310 And here, I can actually read what is the content of each of these Hacker News news pieces. 104 105 00:10:15,310 --> 00:10:19,900 So perfect. So, now our app works beautifully. 105 106 00:10:19,900 --> 00:10:24,870 Let's do a little bit of refactoring to reorganize the code in our project in particular. 106 107 00:10:24,870 --> 00:10:29,430 I don't really like how our WebView is sitting in the same file as our DetailView. 107 108 00:10:29,490 --> 00:10:35,010 Let's move our WebView out of our DetailedView by creating a New File in our views folder which is 108 109 00:10:35,010 --> 00:10:45,380 going to be a Swift File, and this is going to be called our WebView. And then I'm going to cut it out 109 110 00:10:45,380 --> 00:10:46,310 of here, 110 111 00:10:46,370 --> 00:10:53,450 delete the import, and paste it into our WebView, and add the import 111 112 00:10:53,450 --> 00:10:53,990 back, 112 113 00:10:57,130 --> 00:11:04,630 as well as add the import for SwiftUI, so that it knows about the context and UIViewRepresentable. 113 114 00:11:04,640 --> 00:11:12,050 And we can change this output to, again, a WKWebView. 114 115 00:11:13,450 --> 00:11:20,800 So, now we have this reusable component which is a WebView, so that in the future if we wanted to build 115 116 00:11:20,830 --> 00:11:28,630 a WebView in our SwiftUI components, we can simply just tap into this structure. And that completes 116 117 00:11:28,630 --> 00:11:29,400 the project. 117 118 00:11:29,410 --> 00:11:35,410 I knew that this was a very challenging tutorial that built on a lot of Swift programming concepts, 118 119 00:11:35,410 --> 00:11:40,840 but it allowed us to revisit and review everything that we've learned so far. 119 120 00:11:40,840 --> 00:11:46,300 In addition, we also cover some advanced topics like using the observer pattern for state management. 120 121 00:11:46,450 --> 00:11:49,290 So well done for making it through this far. 121 122 00:11:49,360 --> 00:11:55,150 Now, in this lesson, we've reviewed a lot of the concepts that we learned in the course previously, 122 123 00:11:55,150 --> 00:12:03,730 such as networking, URL session, JSON decoding. And we've also looked at how we can create a SwiftUI based 123 124 00:12:03,790 --> 00:12:14,260 list view with a NavigationLink inside that takes us to a DetailView which relies on a UIKit component 124 125 00:12:14,350 --> 00:12:17,860 which we've converted to be used with SwiftUI. 125 126 00:12:17,860 --> 00:12:22,660 We've also looked at a more advanced way of managing state. 126 127 00:12:23,200 --> 00:12:28,040 So we've created our data model namely our network manager here. 127 128 00:12:28,060 --> 00:12:35,950 We've made it an ObservableObject, so that it can publish certain properties that it has access to, and 128 129 00:12:36,220 --> 00:12:44,410 other objects can subscribe to the networkManager and listen for changes in those properties in order 129 130 00:12:44,410 --> 00:12:48,140 to update its views accordingly. 130 131 00:12:48,250 --> 00:12:51,740 So that's quite a lot of stuff that's been jam-packed in here. 131 132 00:12:52,360 --> 00:12:58,650 So where does this leave us with SwiftUI? SwiftUI is very, very new. 132 133 00:12:58,660 --> 00:13:05,620 So in the coming days, weeks, and months, I would not be surprised if SwiftUI completely changes where 133 134 00:13:05,620 --> 00:13:12,280 maybe there will be a native SwiftUI WebView, and we don't have to use UIViewRepresentable anymore, 134 135 00:13:12,820 --> 00:13:18,560 or the way that we work with ObservedObjects and ObservableObjects might change as well. 135 136 00:13:18,580 --> 00:13:25,720 In fact, even within the last few days, the way than Apple showed us how to work with ObservedObjects 136 137 00:13:25,840 --> 00:13:31,660 and ObservableObjects already changed since when they announced it at WWDC. 137 138 00:13:31,690 --> 00:13:37,150 So for those you guys here, remember what Swift version 1 was like? 138 139 00:13:37,150 --> 00:13:40,660 I can see that there's gonna be a lot of changes yet to come. 139 140 00:13:40,660 --> 00:13:44,890 But the good part is that we get to stay on top of the changes. 140 141 00:13:45,130 --> 00:13:52,870 So if you are somebody who doesn't like working with buggy software and beta testing for Apple to be 141 142 00:13:52,870 --> 00:13:58,580 able to report errors, and let them know what needs to be done, what's wrong, what needs to be fixed, 142 143 00:13:58,690 --> 00:14:03,880 if you prefer to work with stable code and stable components, 143 144 00:14:03,880 --> 00:14:09,700 also, if you're actually building a very serious app, I actually recommend sticking with UIKit for now. 144 145 00:14:10,660 --> 00:14:18,400 SwiftUI is going to take maybe three to five years to mature before the code is actually stable and usable 145 146 00:14:18,430 --> 00:14:20,820 to create anything that's serious. 146 147 00:14:21,070 --> 00:14:28,990 But meanwhile, it's really fun to get started and to be at the bleeding edge and be an early adopter 147 148 00:14:29,050 --> 00:14:31,610 to see how this technology develops. 148 149 00:14:31,670 --> 00:14:37,720 So I would love to know what you think of SwiftUI, and if you like it, if you don't like it, what your 149 150 00:14:37,720 --> 00:14:39,890 thoughts are on this technology. 150 151 00:14:40,000 --> 00:14:45,370 So feel free to leave your comments in the Q-and-A section or hit me up on Twitter @yu_angela. 151 152 00:14:45,430 --> 00:14:52,380 In the next lesson, I'm going to talk to you about something called Project Catalyst which is 152 153 00:14:52,380 --> 00:15:01,290 going to allow us to easily turn our iOS apps for iPhones and iPads straight into a Mac application 153 154 00:15:01,650 --> 00:15:04,110 just by doing a few things. 154 155 00:15:04,110 --> 00:15:06,680 So for all of that and more, I'll see you there..