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..
