0
1
00:00:00,750 --> 00:00:01,050
All right.
1

2
00:00:01,060 --> 00:00:06,320
So, so far we've looked at all four of the CRUD capabilities that Core Data offers.
2

3
00:00:06,390 --> 00:00:12,510
So we've looked at creating, reading, updating, and destroying data using the context, and once we're happy
3

4
00:00:12,510 --> 00:00:17,500
with our changes, then we've committed those changes to our persistent container.
4

5
00:00:17,820 --> 00:00:23,750
So, in this lesson, I want to talk about how you can query items using Core Data.
5

6
00:00:23,790 --> 00:00:29,970
So in order to do this, we're going to give our app a little bit more functionality, and the functionality
6

7
00:00:29,970 --> 00:00:35,580
that we want is having search capability, and adding that to our table view.
7

8
00:00:35,670 --> 00:00:42,480
So I want to be able to type in part of or completely a to-do list item. I want our table view to update
8

9
00:00:42,480 --> 00:00:46,500
to show me all of the items that are related with that searched him.
9

10
00:00:46,500 --> 00:00:52,510
So for example, I could have something like, you know, buy milk and buy eggs.
10

11
00:00:52,620 --> 00:00:56,140
and I just want to search for "buy" to see what I need to get from the supermarket.
11

12
00:00:56,400 --> 00:01:01,740
So in order to do that, we're going to go into our trusted object library and we're going to search for
12

13
00:01:02,220 --> 00:01:05,760
a search bar. A little bit circular there.
13

14
00:01:05,910 --> 00:01:11,430
But the one that we want is the Search Bar, not the Search Bar and Search Display controller because
14

15
00:01:11,430 --> 00:01:14,090
we're going to implement a really simple search bar.
15

16
00:01:14,190 --> 00:01:17,120
So I'm going to drag it on to our table view
16

17
00:01:17,220 --> 00:01:20,880
and I'm going to place it just below the navigation bar,
17

18
00:01:21,150 --> 00:01:23,170
so above the table view.
18

19
00:01:23,370 --> 00:01:29,040
So the next thing is to set our view controller as the delegate for the search bar, so that whenever there's
19

20
00:01:29,040 --> 00:01:34,590
any changes inside the search bar like, say, when somebody hits the search button, then this is the class
20

21
00:01:34,590 --> 00:01:35,780
that's going to be informed,
21

22
00:01:35,820 --> 00:01:40,510
and we're going to deal with whatever they type in there inside our TodoListViewController. 
22

23
00:01:40,740 --> 00:01:46,330
So I'm going to say UISearchBarDelegate.
23

24
00:01:46,890 --> 00:01:52,080
Now, previously, every single time we've declared our view controller as a delegate of something. We also have
24

25
00:01:52,080 --> 00:01:57,930
to make an IBOutlet for our search bar. And then inside viewDidLoad, say something like searchBar.delegate
25

26
00:01:57,960 --> 00:01:58,770
= self.
26

27
00:01:58,770 --> 00:02:04,830
So we're familiar with these two steps, adding the protocol in the class declaration, and also setting
27

28
00:02:04,830 --> 00:02:07,280
the outlet's delegate as self.
28

29
00:02:07,340 --> 00:02:12,830
Now, this is optional, so you can either do it in code or
29

30
00:02:12,870 --> 00:02:20,040
the alternative is you can simply hit control, drag, and point to this little yellow icon which represents
30

31
00:02:20,130 --> 00:02:21,220
the view controller.
31

32
00:02:21,330 --> 00:02:27,450
And if you let go, you see that there is a delegate for this outlet that you can set as the view controller
32

33
00:02:27,720 --> 00:02:30,200
which, remember, the yellow icon represents.
33

34
00:02:30,220 --> 00:02:34,950
So make sure that you actually originat it from the search bar, rather than from somewhere else like,
34

35
00:02:34,950 --> 00:02:36,550
say, the table view, right?
35

36
00:02:36,600 --> 00:02:40,770
Because in this case, it's got a data source and delegate, and you can see that they're already set up
36

37
00:02:41,610 --> 00:02:42,350
to be
37

38
00:02:42,390 --> 00:02:42,750
our
38

39
00:02:42,780 --> 00:02:43,910
View Controller class.
39

40
00:02:44,100 --> 00:02:51,780
So it might even be easier going from the document outline and dragging it to the yellow icon, and then
40

41
00:02:51,780 --> 00:02:53,150
hitting delegate.
41

42
00:02:53,190 --> 00:02:58,590
So the next step if we go back into our TodoListViewController is we need to add some delegate methods
42

43
00:02:58,950 --> 00:03:02,160
in order to make the UISearchBarDelegate work, right?
43

44
00:03:02,160 --> 00:03:08,580
So what we can do is right at the bottom below loadItems, we can add the delegate method and it's called
44

45
00:03:08,620 --> 00:03:11,570
a searchBar.
45

46
00:03:11,640 --> 00:03:18,420
Usually, so for a lot of these methods, as long as you're aware they exist, you can pretty much guess what you
46

47
00:03:18,420 --> 00:03:24,360
should start typing in order to get this list of suggestions come up. And you can scroll through them
47

48
00:03:24,390 --> 00:03:28,770
looking at the information texts as to what each one does
48

49
00:03:29,040 --> 00:03:36,300
until you find the one that you want which is, in my case, searchBarSearchButtonClicked.
49

50
00:03:36,420 --> 00:03:41,790
So this tells a delegate that the search button was tapped and that is the point where we want to reload
50

51
00:03:41,790 --> 00:03:45,800
our table view using the text that the user has inputted.
51

52
00:03:46,050 --> 00:03:49,870
So let's hit enter and insert that delegate function in there.
52

53
00:03:49,890 --> 00:03:55,490
Now, some of you might wonder if we have so many of these delegates saying, you know, we have 
53

54
00:03:55,500 --> 00:04:02,400
UISearchBarDelegate, then at a later stage, we decide to add like a picker view, UIPickerViewDelegate, then we 
54

55
00:04:02,460 --> 00:04:07,680
ddecide to have one which is UIImagePickerControllerDelegate.
55

56
00:04:07,710 --> 00:04:13,700
If we have all of these stacking up because we need all of them in our app inside the same view controller,
56

57
00:04:13,710 --> 00:04:17,490
inside the same screen, then it's going to start getting pretty cramped up here.
57

58
00:04:17,670 --> 00:04:24,110
And you've also got different delegate methods that relate to each of these bits of functionality,
58

59
00:04:24,120 --> 00:04:28,390
for example, the SearchBar or the PickerView, ImagePickerController.
59

60
00:04:28,620 --> 00:04:32,080
And should they really all be crammed into the same class?
60

61
00:04:32,100 --> 00:04:35,490
I mean, it seems like it's going to get a little bit tight on space, right?
61

62
00:04:35,640 --> 00:04:40,710
Well, the alternative that we can use that you're going to see in a lot of projects that you download from
62

63
00:04:40,710 --> 00:04:47,100
GitHub, or out there in the wild, is this is the closing brace for our class and everything inside is our
63

64
00:04:47,100 --> 00:04:49,440
TodoListViewController class.
64

65
00:04:49,440 --> 00:05:00,430
Now, if we go outside of the last curly brace and we create an extension, then we can extend the functionality
65

66
00:05:00,880 --> 00:05:09,260
of our TodoListViewController, and we can set it to be a UISearchBarDelegate.
66

67
00:05:09,640 --> 00:05:16,900
So the advantage of this is that we can split up the functionality of our view controller and we can have
67

68
00:05:17,170 --> 00:05:20,560
specific parts that are responsible for specific things.
68

69
00:05:20,560 --> 00:05:27,790
So for example, this extension extends our base view controller and gives it the extra power or the extra
69

70
00:05:27,790 --> 00:05:31,240
functionality of being able to handle search bar methods.
70

71
00:05:31,360 --> 00:05:36,840
So the other advantage is that when you look up here, you can see that we've got the base class here
71

72
00:05:36,910 --> 00:05:39,160
and we've got our extension down here.
72

73
00:05:39,280 --> 00:05:45,610
And one of the downsides of MVC or the model-view-controller pattern that Apple is such a big fan of
73

74
00:05:45,940 --> 00:05:53,780
is that your C starts getting really, really big, and it basically becomes like tiny "M," tiny "V," and massive
74

75
00:05:53,790 --> 00:06:00,580
"C." You often see these gigantic view controllers, especially when you look at Apple's example projects,
75

76
00:06:00,850 --> 00:06:02,560
and they just start getting really, really big.
76

77
00:06:02,560 --> 00:06:09,830
So it's really important that you modularize and try to split up the functionality as much as you can,
77

78
00:06:09,940 --> 00:06:15,580
not just for code organization, which is handy, but also so that when you come to debug it, you can narrow
78

79
00:06:15,580 --> 00:06:20,580
down on which section you need to look at, instead of going through the entire page, right?
79

80
00:06:20,980 --> 00:06:28,510
So for example, if we had issues with our search bar, then we can navigate straight down to our extension
80

81
00:06:28,540 --> 00:06:34,000
that deals with all of the search bar functionality, and we can read only, you know, maybe 10 lines, rather
81

82
00:06:34,000 --> 00:06:35,620
than 100 lines of the page.
82

83
00:06:35,620 --> 00:06:42,910
So, so far we've been using these MARK comments in order to be able to look at our view controller and
83

84
00:06:42,910 --> 00:06:49,290
have this quick breakdown of what are the different sections, and what are the methods in each section.
84

85
00:06:49,450 --> 00:06:55,840
But now we have this extension, and even though the extension, unfortunately, doesn't allow you to rename
85

86
00:06:55,840 --> 00:07:03,480
it, you can still put a MARK above it so that you can see it as a separate section.
86

87
00:07:03,490 --> 00:07:14,470
So we'll call this "Search bar methods." And when we go into our file now, we can see our main class,
87

88
00:07:14,470 --> 00:07:19,000
as well as our extension class which is responsible for the search bar methods.
88

89
00:07:19,000 --> 00:07:26,380
So this is a very Swifty kind of pattern and you're going to see this pretty much everywhere. And usually
89

90
00:07:26,380 --> 00:07:32,800
as a rule of thumb, whenever I want to create a new protocol here in the class declaration line,
90

91
00:07:32,800 --> 00:07:39,440
I tend to create a new extension and group the protocol methods together, like we're going to do now.
91

92
00:07:39,490 --> 00:07:47,380
So inside our TodoListViewController extension where we are extending the functionality with a search
92

93
00:07:47,380 --> 00:07:53,620
bar and some search bar methods, we've got this delegate method which is going to be triggered once the
93

94
00:07:53,620 --> 00:07:56,530
user presses the search button on the search bar.
94

95
00:07:56,530 --> 00:08:02,740
So this is a good point for us to query our database and try to get back the results that the user is
95

96
00:08:02,740 --> 00:08:03,460
searching for.
96

97
00:08:03,460 --> 00:08:09,140
So as always, in order to read from the context, we always have to create a request and we have to declare
97

98
00:08:09,140 --> 00:08:10,830
the request data type.
98

99
00:08:10,830 --> 00:08:19,550
So NSFetchRequest and it's going to return an array of items, and we're going to set this to equal
99

100
00:08:20,480 --> 00:08:23,190
Item.fetchRequest.
100

101
00:08:23,210 --> 00:08:30,740
Now, the next step is we have to specify what is going to be our filter, right? What is going to be our
101

102
00:08:30,740 --> 00:08:31,830
query?
102

103
00:08:32,090 --> 00:08:35,510
And we do that using something called an NSPredicate.
103

104
00:08:35,570 --> 00:08:41,750
But before we do that, let's first have a look at what is the data that we get back when the user clicks
104

105
00:08:41,750 --> 00:08:43,720
on the search button in the search bar.
105

106
00:08:43,910 --> 00:08:52,650
So let's go ahead and just print out the searchBar.text, and let's go ahead and run our app.
106

107
00:08:52,670 --> 00:08:53,000
All right.
107

108
00:08:53,000 --> 00:08:56,160
So the first thing that we see is that we now have a search bar.
108

109
00:08:56,300 --> 00:08:58,570
Yay! That was pretty easy, right?
109

110
00:08:58,610 --> 00:09:06,290
And the first thing I'm going to do is I'm going to hit command K or go to Hardware, and keyboard, and
110

111
00:09:06,350 --> 00:09:11,180
Toggle Software Keyboard. So command K does exactly the same thing and it basically pops up and pops
111

112
00:09:11,180 --> 00:09:19,940
down the keyboard on screen, and then I'm going to, for example, type "Save" in order to pull up all the
112

113
00:09:19,940 --> 00:09:26,570
items that contain the words "Save," either in their title, and then I'm going to hit search. And this is
113

114
00:09:26,570 --> 00:09:32,750
the point where our searchBarSearchButtonClicked delegate method gets fired and it runs everything
114

115
00:09:32,750 --> 00:09:33,790
that's inside.
115

116
00:09:33,830 --> 00:09:39,800
And so our print statement prints out what the searchBar.text! at this point is, and it's the word that
116

117
00:09:39,800 --> 00:09:41,420
we entered which is "Save."
117

118
00:09:41,720 --> 00:09:44,540
Okay, so that worked pretty nicely.
118

119
00:09:44,700 --> 00:09:49,580
It's always a good idea to check along the way to make sure that all your presumptions are right and all
119

120
00:09:49,580 --> 00:09:54,520
your setup, especially with these UIElements have not gone awry.
120

121
00:09:54,710 --> 00:10:02,930
So we now have this request and we need to modify it so that we tag on a query that specifies what we
121

122
00:10:02,930 --> 00:10:05,510
want to get back from the database.
122

123
00:10:05,510 --> 00:10:11,930
So in order to query objects using Core Data, we need to use something called an NSPredicate.
123

124
00:10:11,930 --> 00:10:19,700
So we can say, for example, let predicate = NSPredicate and we're going to initialize it using
124

125
00:10:19,760 --> 00:10:21,050
a format.
125

126
00:10:21,050 --> 00:10:27,410
So the format, as you can see from the placeholder, takes a string and the string is a little bit scary
126

127
00:10:27,410 --> 00:10:33,440
because you're now typing in free text. And in our case, what we would do is we would say "title," 
127

128
00:10:33,440 --> 00:10:38,290
we're going to look at the title attribute of each of our items in our itemArray,
128

129
00:10:38,630 --> 00:10:42,510
and we're going to check that it CONTAINS a value.
129

130
00:10:42,620 --> 00:10:49,410
So this is the argument that we're going to substitute into this percentage, "at" sign.
130

131
00:10:49,520 --> 00:10:54,350
And I'm going to talk about why all of this looks so different from what we've been doing in Swift in just
131

132
00:10:54,350 --> 00:11:00,860
a moment, but let's just set it up first. And the argument is, of course, what we printed out in our print
132

133
00:11:00,860 --> 00:11:04,850
statement which is the searchBar.text.
133

134
00:11:04,850 --> 00:11:12,080
And so when we hit the search button, then whatever we have entered inside the searcBar at that time
134

135
00:11:12,080 --> 00:11:19,880
point is going to be passed in to this method into this part, and replacing this percentage, "at" sign.
135

136
00:11:20,120 --> 00:11:27,140
So then our query becomes "For all the items in the item array, look for the ones where the title of the
136

137
00:11:27,140 --> 00:11:30,230
item contains this text."
137

138
00:11:30,230 --> 00:11:36,410
So this is pretty unfamiliar if you have only been working with Swift.
138

139
00:11:36,410 --> 00:11:42,310
This part might look quite familiar to you if you've ever used or looked at Objective-C code.
139

140
00:11:42,440 --> 00:11:49,310
And the reason is because NSPredicate is basically a foundation class that specifies how data should
140

141
00:11:49,310 --> 00:11:55,560
be fetched or filtered. It's essentially a query language which is like some sort of weird lovechild
141

142
00:11:55,610 --> 00:12:02,390
between the SQL WHERE clause and a rejects or regular expression. It's meant to be similar to natural
142

143
00:12:02,390 --> 00:12:05,920
language like how you would speak in English.
143

144
00:12:06,080 --> 00:12:13,250
But there's a whole bunch of modifiers and logical conditions that you have access to that you can put
144

145
00:12:13,250 --> 00:12:15,440
inside this format string.
145

146
00:12:15,650 --> 00:12:17,990
So let's take a look at those.
146

147
00:12:18,140 --> 00:12:24,590
So a really good resource is actually on the Realm blog, and even though we're not using Realm yet, we're
147

148
00:12:24,590 --> 00:12:26,300
actually still using Core Data.
148

149
00:12:26,300 --> 00:12:31,710
When you query items inside Realm, they also use the same thing which is NSPredicate.
149

150
00:12:31,760 --> 00:12:38,390
So they've made this beautiful PDF that is, essentially, NSPredicate Cheatsheet which you can download
150

151
00:12:38,450 --> 00:12:42,100
from this link here which I'll include in the resources for this lesson.
151

152
00:12:42,090 --> 00:12:45,310
But, essentially, you can have a look at how the string is structured,
152

153
00:12:45,440 --> 00:12:45,680
right?
153

154
00:12:45,680 --> 00:12:51,650
So remember that the percentage "at" sign substitutes any sort of argument that you want to pass in, and
154

155
00:12:51,650 --> 00:12:57,230
you can use most of your basic comparisons like left hand is equal to right hand, or left hand is greater
155

156
00:12:57,230 --> 00:13:02,940
than or equal to the right hand, as well as everything that we've been using so far.
156

157
00:13:03,080 --> 00:13:05,680
But it's also got some of these special words in all caps.
157

158
00:13:05,690 --> 00:13:11,780
For example, the word like "BETWEEN," right? The left hand expression is BETWEEN or equal to the right hand
158

159
00:13:11,780 --> 00:13:13,490
expression.
159

160
00:13:13,760 --> 00:13:16,600
And you can compound your predicates together
160

161
00:13:16,770 --> 00:13:26,820
by using the "AND," "OR," and "NOT." So you can say that the age is equal to 40 AND the price is greater than 67.
161

162
00:13:26,850 --> 00:13:34,350
I don't know in which case you love to look for something that has age over 40 and price over
162

163
00:13:34,430 --> 00:13:38,280
67. Well, maybe wines, I guess. That works.
163

164
00:13:38,520 --> 00:13:41,320
I don't know why I was thinking about humans or pets.
164

165
00:13:41,380 --> 00:13:44,160
That's really bizarre. Anyways--
165

166
00:13:44,790 --> 00:13:50,730
So it's also got things like string comparison operators which is what we use which is the "CONTAINS"
166

167
00:13:51,030 --> 00:13:58,530
because our title is a string and we want to check to make sure that the titles of each of those items
167

168
00:13:58,710 --> 00:14:04,680
contains, i.e., it can partly contain the text that we're searching for, because we're not going to enter
168

169
00:14:04,710 --> 00:14:07,650
the exact word that we're looking for.
169

170
00:14:07,740 --> 00:14:12,630
If we're looking to try and pull up the items like "buy milk," and "buy bread," then it's not very useful
170

171
00:14:12,630 --> 00:14:14,160
just searching for "buy milk,"
171

172
00:14:14,200 --> 00:14:15,720
so that "buy milk" pops up, right?
172

173
00:14:15,770 --> 00:14:18,760
We want to look at all the things that contains the word "buy."
173

174
00:14:18,960 --> 00:14:24,840
Now, if you wanted an exact match, then you might use something like "MATCHES," right? so that it exactly
174

175
00:14:24,870 --> 00:14:26,420
equals the right-hand side.
175

176
00:14:26,430 --> 00:14:30,750
So when you're dealing with strings, then these are some good ones to work with.
176

177
00:14:30,880 --> 00:14:36,330
For all the other data types, then usually you'd be using these basic comparatives when you're working
177

178
00:14:36,330 --> 00:14:37,970
with numbers especially.
178

179
00:14:38,040 --> 00:14:40,030
So this is a brilliant Cheatsheet.
179

180
00:14:40,050 --> 00:14:41,490
Have a look at it. Study it
180

181
00:14:41,490 --> 00:14:46,620
if you're going to be querying a database. And you can do a lot of really sophisticated stuff with it
181

182
00:14:47,160 --> 00:14:50,400
and it's still relatively short and easily readable.
182

183
00:14:50,400 --> 00:14:54,750
And they've also got some tips, tricks, and examples which work with Core Data as well.
183

184
00:14:54,750 --> 00:15:00,630
It's basically how you search your databases using Realm or using Core Data.
184

185
00:15:01,080 --> 00:15:03,270
And another good article is this one on
185

186
00:15:03,270 --> 00:15:08,970
NSPredicate written by Mattt Thompson who was one of the creators of Alamofire that we've been
186

187
00:15:08,970 --> 00:15:09,690
using so far.
187

188
00:15:09,720 --> 00:15:11,490
So a really good article on this
188

189
00:15:11,490 --> 00:15:13,100
if you want to read out more on it.
189

190
00:15:13,200 --> 00:15:17,970
And one of the things you need to remember about string comparisons using NSPredicate, as you'll
190

191
00:15:17,970 --> 00:15:24,180
find in this article, is that string comparisons are by default case and diacritic sensitive.
191

192
00:15:24,240 --> 00:15:30,450
So case, obviously, means upper-lower case, and diacritic refers to these little marks above your letters.
192

193
00:15:30,450 --> 00:15:37,470
So, for example, in French, you have the "circonflexe" and the "grave" accents, or in German, you have the "umlaut." 
193

194
00:15:37,470 --> 00:15:43,530
So these are the diacritics. And you know for us to implement search, do we really want it to be case-sensitive
194

195
00:15:43,530 --> 00:15:44,750
and diacritic-sensitive?
195

196
00:15:44,760 --> 00:15:45,510
Probably not.
196

197
00:15:45,600 --> 00:15:51,630
So you can modify that by just adding the square brackets and including "c" and "d." So "c" stands for case
197

198
00:15:51,630 --> 00:15:57,190
and "d" stands for diacritic, and it makes it, basically, insensitive to these two things.
198

199
00:15:57,270 --> 00:16:03,820
So let's go back to our code and modify it with our new knowledge. So we can add it after the "CONTAINS"
199

200
00:16:03,830 --> 00:16:05,510
And we're just going to add "CD" to it.
200

201
00:16:05,670 --> 00:16:11,470
So, now we have structured our query and we're going to add our query to our request, so we can say 
201

202
00:16:11,470 --> 00:16:14,580
request.predicate = predicate.
202

203
00:16:14,590 --> 00:16:21,450
All right, so now that we've created our predicate which specifies how we want to query our database,
203

204
00:16:21,780 --> 00:16:27,210
the next thing that we can do is we can actually sort the data that we get back from the database in
204

205
00:16:27,300 --> 00:16:28,550
any order of our choice.
205

206
00:16:28,770 --> 00:16:38,100
So we can create a sortDescriptor that is a NSSortDescriptor, and we can say that we want to sort
206

207
00:16:38,100 --> 00:16:46,110
using the key that's the titles of each of the Items, and we can sort it in alphabetical order by saying
207

208
00:16:46,210 --> 00:16:47,610
ascending equals true.
208

209
00:16:47,670 --> 00:16:56,280
So, now we can add the sortDescriptor to our request by saying request.sortDescriptor, so it's really
209

210
00:16:56,280 --> 00:17:02,490
important that you notice here that this property is actually plural and that's because it expects an
210

211
00:17:02,490 --> 00:17:04,650
array of NSSortDescriptors.
211

212
00:17:04,650 --> 00:17:08,540
But in our case, we actually just want to specify a single sort rule.
212

213
00:17:08,610 --> 00:17:13,950
So we're going to say sortDescriptors equals an array of sortDescriptors, but it only contains a single
213

214
00:17:13,950 --> 00:17:16,770
item and that's a perfectly valid code.
214

215
00:17:17,100 --> 00:17:22,650
So, now all we have to do is to run our request and fetch the results, right?
215

216
00:17:22,830 --> 00:17:28,050
So if you have a look in our loadItems method, you can see that we've got a block of code that does
216

217
00:17:28,140 --> 00:17:29,530
exactly that.
217

218
00:17:29,550 --> 00:17:39,750
So we can copy and paste it over here so that we can try using our context to fetch these results from
218

219
00:17:39,750 --> 00:17:40,920
our persistent store
219

220
00:17:40,920 --> 00:17:47,190
that satisfy the rules that we specified for our request which is, namely, the title should contain
220

221
00:17:47,250 --> 00:17:54,570
whatever is in the searchBar, and the results should come back with their titles assorted in ascending
221

222
00:17:54,600 --> 00:17:55,570
alphabetical order.
222

223
00:17:55,650 --> 00:18:03,540
So then we assigned the results of that fetch to our itemArray and we now need to reload our
223

224
00:18:03,540 --> 00:18:10,290
tableView so that we retrigger the cellForRowAt indexPath methods and we update our tableView with the
224

225
00:18:10,320 --> 00:18:13,920
current itemArray which contains the results of the search.
225

226
00:18:13,920 --> 00:18:19,890
So, now as I always say, whenever you find yourself copying and pasting large chunks of code, then it's
226

227
00:18:19,890 --> 00:18:25,470
probably a good trigger for you to think about whether if you can refactor your code so that it's more
227

228
00:18:25,470 --> 00:18:26,040
succinct
228

229
00:18:26,250 --> 00:18:30,340
and you're not repeating yourself, but instead keeping all code dry.
229

230
00:18:30,450 --> 00:18:36,750
But before you refactor your code, you should always make sure that you test your assumptions and make
230

231
00:18:36,750 --> 00:18:39,090
sure that the current code works.
231

232
00:18:39,180 --> 00:18:44,510
So let's do that now. Let's run our app and see if it works.
232

233
00:18:44,520 --> 00:18:44,820
All right.
233

234
00:18:44,820 --> 00:18:49,810
So I've added a whole bunch of items that all contain the word "Save."
234

235
00:18:49,980 --> 00:18:54,120
So there's four items that contain a capitalized Save.
235

236
00:18:54,190 --> 00:18:58,360
There's one lowercase save and this one save with a diacritic.
236

237
00:18:58,620 --> 00:19:06,210
So if we go into our search bar and search for the word "Save" with a capital "S," we're going to look inside
237

238
00:19:06,240 --> 00:19:11,480
all of these items and look for the ones that contain the word "Save,"
238

239
00:19:11,550 --> 00:19:15,490
and our query is case and diacritic insensitive.
239

240
00:19:15,780 --> 00:19:18,240
So let's go ahead and hit search.
240

241
00:19:18,240 --> 00:19:24,870
Which, of course, triggers the searchBarSearchButtonClicked delegate method and executes all of this
241

242
00:19:24,870 --> 00:19:25,470
code.
242

243
00:19:25,650 --> 00:19:33,240
And when we get back, there's all of the items that contain the word "Save" and it's case and diacritic insensitive.
243

244
00:19:33,240 --> 00:19:38,510
So, now that we've proven that our code works, then it's a good time to refactor our code.
244

245
00:19:38,730 --> 00:19:42,700
So one of the first things is that we probably don't need this constant,
245

246
00:19:42,840 --> 00:19:43,130
right?
246

247
00:19:43,140 --> 00:19:46,830
We can simply replace it with request.predicate
247

248
00:19:50,470 --> 00:19:58,560
and we can delete this line. So two become one. And we can replace this let sortDescriptor with 
248

249
00:19:58,710 --> 00:20:00,250
request.sortDescriptor.
249

250
00:20:00,450 --> 00:20:06,670
Now, before we can delete this line, we have to realize that sortDescriptors expects an array of 
250

251
00:20:06,710 --> 00:20:07,340
NSSortDescriptors.
251

252
00:20:07,500 --> 00:20:14,280
So we have to add these square brackets around this line on the right-hand side in order to make it equivalent
252

253
00:20:14,610 --> 00:20:15,740
to this.
253

254
00:20:15,840 --> 00:20:18,070
And now we can finally delete that line.
254

255
00:20:18,300 --> 00:20:20,840
So, now we've gone down from four to two.
255

256
00:20:21,030 --> 00:20:28,370
And finally, as I said before, we've got this do-catch block that's repeated inside our loadItems method.
256

257
00:20:28,650 --> 00:20:35,740
So I want to be able to call loadItem, rather than having to write out all of this code again.
257

258
00:20:35,760 --> 00:20:44,340
So what I can do is I can comment out this code and I can modify this function to take a parameter that
258

259
00:20:44,400 --> 00:20:46,310
is the request.
259

260
00:20:46,350 --> 00:20:55,080
So this is going to be of data type NSFetchRequest and it's going to return an array of Items.
260

261
00:20:55,080 --> 00:21:02,070
So, now instead of repeating this do-catch block, I can simply say loadItems and the request I want to
261

262
00:21:02,070 --> 00:21:08,080
make is this modified request which contains the query and the sort descriptors.
262

263
00:21:08,340 --> 00:21:13,880
So I can say loadItems with request and the request is this one.
263

264
00:21:13,950 --> 00:21:22,020
So the only problem here is that loadItems(request request) doesn't really make a lot of sense in English,
264

265
00:21:22,020 --> 00:21:22,740
right?
265

266
00:21:22,830 --> 00:21:27,660
And what you notice with Swift is that it's really pro-natural language.
266

267
00:21:27,660 --> 00:21:32,560
So you want to have your method calls sound almost like they make sense in English.
267

268
00:21:32,610 --> 00:21:37,750
So having "request: request" is kind of confusing and doesn't make a lot of sense.
268

269
00:21:37,860 --> 00:21:43,110
So we can modify this parameter to also have an external parameter.
269

270
00:21:43,110 --> 00:21:46,900
So this is the external parameter and this is the internal parameter.
270

271
00:21:47,130 --> 00:21:54,600
So the internal parameter is going to be used inside this block of code and the external one is the one
271

272
00:21:54,600 --> 00:21:56,770
that we're going to use when we call the function.
272

273
00:21:56,940 --> 00:21:58,560
So now that reads a little bit better,
273

274
00:21:58,590 --> 00:22:00,590
loadItems(with: request)
274

275
00:22:00,610 --> 00:22:05,130
Right? Now, what's happening is we're creating a new request,
275

276
00:22:05,130 --> 00:22:09,760
then we modify it with our query and our sortDescriptor,
276

277
00:22:10,050 --> 00:22:16,910
and then we pass that request into our loadItems function over here as NSFetchRequest.
277

278
00:22:16,980 --> 00:22:24,750
And then we perform that request by saying context.fetch. So we can now delete this do-catch block
278

279
00:22:24,840 --> 00:22:31,170
and we can also delete tableView.reload data because it's already inside loadItems, and we now have a
279

280
00:22:31,170 --> 00:22:34,460
shorter and much sweeter block of code.
280

281
00:22:34,530 --> 00:22:40,740
Now, because we're passing in the request, and then we're creating a new constant code request,
281

282
00:22:40,740 --> 00:22:41,910
it's a little bit confusing
282

283
00:22:41,910 --> 00:22:44,100
which one is used here.
283

284
00:22:44,250 --> 00:22:49,530
And in fact, we don't really need this line if we're going to pass in the request.
284

285
00:22:49,530 --> 00:22:52,340
We don't need to reinitialize a new request,
285

286
00:22:52,350 --> 00:22:58,740
right? Now, there's just one problem, and Xcode is actually notifying you of it using this little error here,
286

287
00:22:59,580 --> 00:23:06,660
and it's saying right at the beginning when we perform viewDiLoad, we also called loadItems, and this
287

288
00:23:06,660 --> 00:23:12,480
is where we want to load up all of the to-do list items from our persistent container.
288

289
00:23:12,480 --> 00:23:17,250
And at this point, we're not really interested in querying it or sorting it. We just want every single
289

290
00:23:17,250 --> 00:23:20,340
to-do list item so that we can show it in our table view.
290

291
00:23:20,370 --> 00:23:25,980
But now this loadItems method actually expects a parameter.
291

292
00:23:26,250 --> 00:23:27,840
So what can we do?
292

293
00:23:27,930 --> 00:23:36,210
Well, we could maybe copy this line of code and paste it up here, so we can say let request equals just
293

294
00:23:36,240 --> 00:23:42,230
fetch, all of the items from the persistent store, and we can now pass it in as a parameter,
294

295
00:23:42,240 --> 00:23:48,810
say loadItems with request. But this is not really ideal and it's not all that succinct either.
295

296
00:23:49,050 --> 00:23:58,090
So we can actually shorten this code even more by providing our parameter with a default value.
296

297
00:23:58,410 --> 00:24:05,200
So we can say that the request is of type and as fetch request which should fetch an array of items,
297

298
00:24:05,250 --> 00:24:12,420
that's the data type, and if when we call this function and we don't provide a value for the request,
298

299
00:24:12,810 --> 00:24:18,420
then we can have a default value that simply Item.fetchRrequest.
299

300
00:24:18,420 --> 00:24:26,850
So, now we can delete this line of code and we can be safe in knowing that when we call loadItems with
300

301
00:24:26,850 --> 00:24:33,220
request and we provide an argument, then that's the one that we're going to fetch from our context.
301

302
00:24:33,420 --> 00:24:41,880
But if we call on loadItems without a NSFetchRequest Item, then we can simply use the default value
302

303
00:24:41,910 --> 00:24:44,080
which is Item.FetchRequest.
303

304
00:24:44,220 --> 00:24:51,240
And what this allows us to do isup here when we call loadItems, we can simply call it as we did before
304

305
00:24:51,570 --> 00:24:56,560
without giving it any parameters, and we can also delete this line of code.
305

306
00:24:56,640 --> 00:25:03,810
So this method is a little bit complex because we have an external and an internal parameter, but, also,
306

307
00:25:04,050 --> 00:25:10,900
it has a default value in cases where we call loadItems without giving it any parameters.
307

308
00:25:11,070 --> 00:25:17,430
So it's a good idea to have a play around maybe in playgrounds at creating methods that have internal
308

309
00:25:17,550 --> 00:25:25,740
and external parameters just to see how it works, and also to create methods that have default values,
309

310
00:25:25,740 --> 00:25:29,240
so you can see how you can call them and how you can create them.
310

311
00:25:29,280 --> 00:25:35,910
Now, there's just one problem with our search bar and it's the fact that we can actually get back to
311

312
00:25:35,910 --> 00:25:37,510
our original table view.
312

313
00:25:37,590 --> 00:25:42,240
What do we do once we're satisfied with searching for the word "Save"?
313

314
00:25:42,450 --> 00:25:46,050
And we actually want to go back to seeing all of the to-do list items.
314

315
00:25:46,050 --> 00:25:51,460
It doesn't help if we try and click the cross and delete all the search, we can't get back, right?
315

316
00:25:51,470 --> 00:25:54,000
And that's because we haven't written any code to do that yet.
316

317
00:25:54,210 --> 00:25:56,760
So that's what we're going to do in the next lesson.
317

318
00:25:56,760 --> 00:26:02,700
We're going to address that bug and we're going to fix our table view so that we can return to our original
318

319
00:26:02,700 --> 00:26:03,770
state.
319

320
00:26:03,810 --> 00:26:06,470
So for all of that and more, I'll see you on the next lesson.
