0
1
00:00:00,510 --> 00:00:00,940
All right.
1

2
00:00:00,960 --> 00:00:07,590
So, now that we've gotten all the serious parts of our coding out of the way, we've got our messages being
2

3
00:00:07,590 --> 00:00:15,720
saved to our Firebase Firestore, we've got our login and registration routes planned out and working,
3

4
00:00:15,720 --> 00:00:21,690
now it's time to tackle some of those small user experience problems and improve the look and feel of
4

5
00:00:21,690 --> 00:00:22,780
our app.
5

6
00:00:22,860 --> 00:00:29,910
And one glaringly obvious problem that our app has at the moment is that when the user taps in this
6

7
00:00:29,910 --> 00:00:32,480
text field, the keyboard
7

8
00:00:32,640 --> 00:00:38,210
if it rises up will completely cover the text field as well as the send button.
8

9
00:00:38,250 --> 00:00:45,090
Now, on the simulator, we can toggle the keyboard up and down using command K. But the user who's using
9

10
00:00:45,090 --> 00:00:48,380
a physical iPhone cannot do this.
10

11
00:00:48,400 --> 00:00:50,580
Now, what is the solution?
11

12
00:00:50,580 --> 00:00:57,210
Well, the easiest thing would be to figure out what is the height of the keyboard, and then to lift this
12

13
00:00:57,270 --> 00:01:05,060
section here with the text field and the send button up to the top so that it rises up to about here,
13

14
00:01:05,310 --> 00:01:12,030
and it's no longer overlapped by the keyboard. But, unfortunately, especially if you're somebody who has
14

15
00:01:12,120 --> 00:01:19,550
a keen eye for detail, you'll notice that different iPhones have different sized keyboards.
15

16
00:01:19,590 --> 00:01:27,390
So that means that if we use a set or hardcoded number to lift this section up, then it will look a
16

17
00:01:27,390 --> 00:01:32,340
little bit weird depending on which iPhone the app is being run on.
17

18
00:01:32,430 --> 00:01:35,120
What can we do instead?
18

19
00:01:35,130 --> 00:01:43,230
Well, we could instead listen for notifications from the operating system when it's going to bring up
19

20
00:01:43,230 --> 00:01:50,760
the keyboard, then see which keyboard, and then write a lot of code to be able to check to see which height
20

21
00:01:50,760 --> 00:01:53,800
it is and adapt our code accordingly.
21

22
00:01:53,920 --> 00:02:00,860
But there's a much simpler solution because we now know how to use third party libraries.
22

23
00:02:00,900 --> 00:02:08,760
So because this is such a commonly needed functionality, whenever you create text fields, it's likely
23

24
00:02:08,760 --> 00:02:15,250
that you'll need some sort of way of moving it up, so that it doesn't get obscured by the keyboard.
24

25
00:02:15,270 --> 00:02:21,780
Lots of people have already written their solutions to it and they've packaged it into a module so that
25

26
00:02:21,780 --> 00:02:27,870
they can reuse it themselves when they're building new apps. And some of these developers are kind enough
26

27
00:02:28,110 --> 00:02:34,440
to share their solutions with the rest of us and we can tap into this functionality without very much
27

28
00:02:34,530 --> 00:02:35,280
work at all.
28

29
00:02:36,720 --> 00:02:42,120
So the package that we're going to be using in this lesson is something called IQKeyboardManagerSwift.
29

30
00:02:42,780 --> 00:02:48,230
And this is a package that's developed by Mr. Qurashi.
30

31
00:02:48,630 --> 00:02:54,360
And the best feature of it is it works codeless, so we don't actually have to write any code.
31

32
00:02:54,360 --> 00:02:56,990
We don't have to change anything about our app.
32

33
00:02:57,090 --> 00:03:05,310
It simply works in the background and lifts our text field so that it doesn't get obscured by the keyboard
33

34
00:03:05,640 --> 00:03:10,140
in all orientations and on all devices.
34

35
00:03:10,350 --> 00:03:17,350
If we scroll down, you can see that there's actually many ways of installing this particular package.
35

36
00:03:17,490 --> 00:03:24,390
And the most commonly used one is probably doing it via CocoaPods. And you already know how to do this.
36

37
00:03:24,390 --> 00:03:30,550
So if you wanted to, you can actually go ahead and incorporate this pod into your project right now.
37

38
00:03:30,750 --> 00:03:37,920
But because this developer has also enabled insulation with the Swift Package Manager, I thought it might
38

39
00:03:37,920 --> 00:03:43,860
be a good opportunity for me to show you how you can add a package with this Swift Package Manager as
39

40
00:03:43,860 --> 00:03:47,820
long as the project supports it.
40

41
00:03:47,820 --> 00:03:53,700
Notice how if we go to the GitHub repository for this project, you can see that on this main page of
41

42
00:03:53,700 --> 00:03:57,590
files, there is a file called Package.swift.
42

43
00:03:57,660 --> 00:04:02,330
This means that this package is able to work with this Swift Package Manager.
43

44
00:04:02,850 --> 00:04:09,150
However, most third party libraries, including the Firebase modules that we incorporated, don't have this
44

45
00:04:09,150 --> 00:04:10,590
feature enabled yet.
45

46
00:04:10,770 --> 00:04:17,220
So it's only for a small subsect of third party libraries that we can actually use the native Swift Package
46

47
00:04:17,220 --> 00:04:17,670
Manager.
47

48
00:04:18,420 --> 00:04:20,640
But how would we go about installing it?
48

49
00:04:21,600 --> 00:04:30,360
Well, if you find a project in GitHub that has a Package.swift file in its main directory,
49

50
00:04:30,480 --> 00:04:33,540
so notice how this is the GitHub domain,
50

51
00:04:33,540 --> 00:04:35,490
this is the user name,
51

52
00:04:35,490 --> 00:04:37,280
and then this is their package name,
52

53
00:04:37,290 --> 00:04:39,080
there's nothing that's coming after here,
53

54
00:04:39,090 --> 00:04:39,360
right?
54

55
00:04:39,390 --> 00:04:42,950
So we're in the root directory of this package.
55

56
00:04:43,020 --> 00:04:50,910
What you need to do is go ahead and just copy this URL, and then head over to your project, go to file,
56

57
00:04:51,390 --> 00:04:54,810
Swift Packages, Add Package Dependency.
57

58
00:04:55,320 --> 00:04:59,710
And now we're going to choose the projects that we want to add the package to.
58

59
00:04:59,730 --> 00:05:01,670
So we're not going to add it to our Pods.
59

60
00:05:01,680 --> 00:05:08,160
We're going to add it directly to our Flash Chat project. And this is also a good point to mention that
60

61
00:05:08,610 --> 00:05:15,270
while the Swift Package Manager is supposed to work alongside CocoaPods or Carthage, or any of the other
61

62
00:05:15,270 --> 00:05:23,150
third party library managers, at the moment, at this current moment in time, so end of October 2019,
62

63
00:05:23,340 --> 00:05:31,230
I'm finding that if you first saw CocoaPods and you add your Swift packages in the xcworkspace to
63

64
00:05:31,230 --> 00:05:35,250
your project, you have far fewer problems than if you do it the other way round.
64

65
00:05:35,280 --> 00:05:41,700
Say, you start off with a normal project, you add the Swift Package, and then you try to add a pod file
65

66
00:05:42,150 --> 00:05:44,220
and install pods onto that project,
66

67
00:05:44,220 --> 00:05:48,960
you get a lot of weird errors that the Xcode team seems to need to work out.
67

68
00:05:48,960 --> 00:05:55,110
So what I recommend is if you're going to use both CocoaPods and Swift Package Manager, then go ahead
68

69
00:05:55,200 --> 00:05:59,440
and install the pods first before you do the package manager side.
69

70
00:05:59,670 --> 00:06:06,000
But in most cases, you'll find that anything that's available on  Swift Package Manager is also available
70

71
00:06:06,000 --> 00:06:06,990
on CocoaPods.
71

72
00:06:07,110 --> 00:06:08,580
But the reverse is not true,
72

73
00:06:08,700 --> 00:06:15,360
there's far more third party libraries on CocoaPods than on Swift Package Manager at least right now.
73

74
00:06:15,390 --> 00:06:21,090
So now that we've selected our project, let's go ahead and hit Next, and then we're going to paste in
74

75
00:06:21,150 --> 00:06:28,470
that URL that we got earlier on which points to the IQKeyboardManager repository on GitHub.
75

76
00:06:28,950 --> 00:06:34,160
So click Next and it's gonna go ahead and find the project.
76

77
00:06:34,170 --> 00:06:38,650
And now it asked for what rules you want to apply to your package.
77

78
00:06:38,670 --> 00:06:43,380
So in this case, we're going to update this particular module.
78

79
00:06:43,470 --> 00:06:50,520
So when the developer of IQKeyboardManager pushes out updates, we're also going to update our project
79

80
00:06:50,880 --> 00:06:57,820
to use the latest version of the keyboard manager up to the next major version.
80

81
00:06:57,840 --> 00:07:03,300
So at the moment, we're on 6.5.3 which supports the latest version of Swift and iOS13,
81

82
00:07:03,300 --> 00:07:09,990
and we're going to say that we want to update to using the next major version which i
82

83
00:07:09,990 --> 00:07:11,070
7.0.0.
83

84
00:07:11,580 --> 00:07:18,220
And the reason why you might want to limit your updates to major versions is that, let's say, 
84

85
00:07:18,240 --> 00:07:21,120
that IQKeyboardManager updates to 8.0.
85

86
00:07:21,120 --> 00:07:26,790
Then it's very likely that it also entails an update in the Swift version,
86

87
00:07:26,850 --> 00:07:29,370
so it might be Swift 6 or Swift 7.
87

88
00:07:29,580 --> 00:07:34,040
And unless you're using the same version of Swift, then your project might break.
88

89
00:07:34,110 --> 00:07:40,880
You can also be even more careful and change to up to next minor update in which case 6.5
89

90
00:07:40,880 --> 00:07:42,310
goes to 6.6,
90

91
00:07:42,440 --> 00:07:46,730
or you can say the exact version that I'm working with right now.
91

92
00:07:46,790 --> 00:07:48,500
This is the least likely to break.
92

93
00:07:48,530 --> 00:07:52,780
But in our case, I recommend going with the next major update.
93

94
00:07:52,880 --> 00:07:58,880
That way we'll be able to benefit from the updates and bug fixes that gets brought to the package when
94

95
00:07:58,940 --> 00:08:02,830
iOS and Xcode inevitably changes.
95

96
00:08:02,890 --> 00:08:09,050
Now it's going to download that module and incorporate it into our project as a library.
96

97
00:08:09,550 --> 00:08:11,360
So go ahead and click Finish.
97

98
00:08:11,440 --> 00:08:17,530
And now when you take a look inside the left-side pane, you'll notice that down at the bottom, we've got
98

99
00:08:17,560 --> 00:08:23,250
our Swift Packaged Dependencies is added and we've got our keyboard manager right there.
99

100
00:08:23,620 --> 00:08:24,400
That's it.
100

101
00:08:24,400 --> 00:08:30,400
That's all we have to do. We didn't have to go into Terminal and we didn't have to do anything extra.
101

102
00:08:30,400 --> 00:08:36,970
This is why it's a really nice way of incorporating third party libraries into your projects in Xcode
102

103
00:08:36,970 --> 00:08:41,060
because it's inbuilt to the existing tooling.
103

104
00:08:41,290 --> 00:08:46,810
But unfortunately, right now, there's just not enough coverage and there aren't enough developers who
104

105
00:08:46,810 --> 00:08:49,930
are making libraries for the Swift Package Manager.
105

106
00:08:50,560 --> 00:08:55,990
I think in two years or three years, the situation will probably change and we'll end up with a much
106

107
00:08:56,080 --> 00:08:59,350
easier way of using these third party dependencies.
107

108
00:08:59,920 --> 00:09:07,750
So, now that we've incorporated the IQKeyboardManager package, all we have to do to enable it is to
108

109
00:09:07,750 --> 00:09:16,450
go to our AppDelegate.swift file, import the IQKeyboardManagerSwift module, and then inside
109

110
00:09:16,450 --> 00:09:18,160
our didFinishLaunchingWithOptions,
110

111
00:09:18,280 --> 00:09:21,960
go ahead and enable the keyboard manager.
111

112
00:09:22,150 --> 00:09:27,700
Now, even though it's not showing that down here under the Swift Package Manager, you basically have to
112

113
00:09:27,700 --> 00:09:32,900
do the same thing whether if you're using CocoaPods or Carthage, or Source code, or SPM.
113

114
00:09:33,850 --> 00:09:42,100
So let's go ahead and open up our AppDelegate.swift, and then import that module which was called
114

115
00:09:42,190 --> 00:09:49,690
IQKeyboardManagersSwift, and down here just below where we've created our Firestore database,
115

116
00:09:49,690 --> 00:10:02,590
we're going to go ahead and tap into the IQKeyboardManager.shared.enable, and set it to true.
116

117
00:10:02,730 --> 00:10:11,070
And we're now ready to go ahead and run our app. And now that we've enabled this third party library,
117

118
00:10:11,130 --> 00:10:18,870
notice what happens when I tap in the text field, it automatically scrolls up the rest of my screen and
118

119
00:10:18,870 --> 00:10:23,020
brings the text field to within view of my keyboard.
119

120
00:10:23,070 --> 00:10:29,050
And if you want, you can even do some more customizations with IQKeyboardManager.
120

121
00:10:29,400 --> 00:10:33,990
So for example, I don't really want this toolbar up here where it says done,
121

122
00:10:34,110 --> 00:10:42,210
it seems a little bit extra. So what I can do is I can go over to the properties and functions of the
122

123
00:10:42,210 --> 00:10:43,440
IQKeyboardManager,
123

124
00:10:43,800 --> 00:10:49,890
so these are all the things that you can do with the keyboard manager, and one of those things is to
124

125
00:10:50,340 --> 00:10:52,950
disable the AutoToolbar.
125

126
00:10:52,950 --> 00:10:56,500
This basically relates to this little area right here.
126

127
00:10:56,670 --> 00:11:03,690
And if I don't want it, then in the same place where I enabled my IQKeyboardManager, I'm going to tap
127

128
00:11:03,690 --> 00:11:12,300
into the keyboard manager and tap into the shared keyboard manager, and go to the enableAutoToolbar
128

129
00:11:12,300 --> 00:11:16,630
property, and set it to false.
129

130
00:11:16,900 --> 00:11:25,820
So, now if I run my app again, you can see that when the keyboard comes up, it doesn't go as high because
130

131
00:11:25,820 --> 00:11:28,930
we've gotten rid of that toolbar.
131

132
00:11:29,060 --> 00:11:35,360
Now, the final thing I'd like to be able to do is to be able to dismiss the keyboard if I click away
132

133
00:11:35,360 --> 00:11:36,050
from it.
133

134
00:11:36,050 --> 00:11:42,380
And right now, if I click anywhere on my table view, nothing actually really happens. But if I take a look
134

135
00:11:42,380 --> 00:11:50,180
at the keyboard manager's documentation right here, you can see that there is a property called
135

136
00:11:50,180 --> 00:11:58,680
shouldResignOnTouchOutside. And this resigns the text field, which means the text field is no longer selected,
136

137
00:11:58,730 --> 00:12:04,790
it kind of deselects the text field effectively if touched outside of the text field.
137

138
00:12:04,790 --> 00:12:11,360
So that means when we tap anywhere other than the text field, it's going to dismiss our keyboard.
138

139
00:12:11,420 --> 00:12:13,580
Let's give that a go shouldResignOnTouchOutside.
139

140
00:12:13,580 --> 00:12:18,320
And I want to pose this as a challenge to you.
140

141
00:12:18,320 --> 00:12:20,540
Can you implement this behavior?
141

142
00:12:20,540 --> 00:12:26,540
Pause the video and write the code so that when we click away from the text field, our keyboard is dismissed.
142

143
00:12:26,630 --> 00:12:32,560
I'll give you a few seconds to pause the video before I show you the solution.
143

144
00:12:32,640 --> 00:12:33,120
Ready?
144

145
00:12:33,120 --> 00:12:37,530
Here's the solution. Again, same as before,
145

146
00:12:37,530 --> 00:12:46,540
and then the property that we copied over just now, and then turn it to true. So now when I tap on the
146

147
00:12:46,540 --> 00:12:53,560
text field, my keyboard responds and pops open. But if I tap away from the text field, it dismisses the
147

148
00:12:53,560 --> 00:13:01,690
keyboard which is a really nice behavior that we've gotten for pretty much just a single line of code.
148

149
00:13:02,020 --> 00:13:04,610
And that's the solution to the challenge.
149

150
00:13:04,750 --> 00:13:11,890
The very last thing I've noticed is that our cell, because it's created from our reusable message cell
150

151
00:13:11,890 --> 00:13:17,770
here, it's still allowing selection which is what's causing this gray background to show up.
151

152
00:13:17,830 --> 00:13:25,750
So we have to select our cell and go to the Attributes Inspector and disable the user interaction checkbox
152

153
00:13:25,750 --> 00:13:28,130
right here.
153

154
00:13:28,190 --> 00:13:35,790
And then, now even if we select these cells, they won't turn gray, like as if it'll do something when we click on
154

155
00:13:35,790 --> 00:13:35,910
it.
155

156
00:13:36,540 --> 00:13:37,660
So that's it.
156

157
00:13:37,920 --> 00:13:41,840
That's all you had to do in order to get this brilliant behavior.
157

158
00:13:41,850 --> 00:13:48,480
This automatic animation, we're basically getting with no code at all, and it means that we can focus
158

159
00:13:48,510 --> 00:13:56,370
on creating the custom parts of our app making our app different from other apps using our creativity,
159

160
00:13:56,700 --> 00:14:03,420
rather than doing a lot of this boilerplate and routine stuff that we might need in a lot of apps.
160

161
00:14:03,420 --> 00:14:04,340
In the next lesson,
161

162
00:14:04,350 --> 00:14:06,560
we're going to be tying up some loose ends
162

163
00:14:06,670 --> 00:14:14,970
and we're going to see how we can get our app to display a different format of message if it came from a
163

164
00:14:14,970 --> 00:14:20,630
recipient versus if it's a message that we sent. For all of that and more,
164

165
00:14:20,700 --> 00:14:21,750
I'll see you on the next lesson.
