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