0
1
00:00:00,550 --> 00:00:00,900
All right.
1

2
00:00:00,930 --> 00:00:08,070
So in the last lesson, we went about setting up our project making sure that we incorporated our
2

3
00:00:08,160 --> 00:00:15,040
TweetSentimentAnalysisClassifier, as well as this external framework, called sSwifter.
3

4
00:00:15,060 --> 00:00:17,350
So we're now all ready to go.
4

5
00:00:17,460 --> 00:00:21,700
And the first thing we're going to do is we're going to go into our ViewController.swift file
5

6
00:00:21,990 --> 00:00:26,940
and we're going to import that framework that we included in the last lesson,
6

7
00:00:27,060 --> 00:00:29,300
and that's Swifter iOS.
7

8
00:00:29,430 --> 00:00:35,930
Now, the next thing to do is to check the documentation for this Swifter framework.
8

9
00:00:36,150 --> 00:00:40,120
And you can see that under Usage, we've already done installation,
9

10
00:00:40,260 --> 00:00:41,520
so we now need to use it.
10

11
00:00:42,180 --> 00:00:47,760
And it tells us that it can be used using three different kinds of authentication protocols that Twitter
11

12
00:00:47,760 --> 00:00:48,290
allows.
12

13
00:00:48,610 --> 00:00:51,300
And you can specify which one you want to use
13

14
00:00:51,420 --> 00:00:54,700
and they give you the example code for how you would do that.
14

15
00:00:54,720 --> 00:01:00,360
Now, you can see over here under our app, we've got a Consumer API Key.
15

16
00:01:00,540 --> 00:01:06,090
And if you click on this link where it says, "Manage keys and access" tokens, then it takes you to an area
16

17
00:01:06,120 --> 00:01:12,120
where you've got your API Key and your API Secret and that's everything that you need to do in order
17

18
00:01:12,120 --> 00:01:17,250
to authenticate yourself as a developer to try and grab data from the Twitter API.
18

19
00:01:17,760 --> 00:01:23,340
So if we head back over here, you can see the one where we have a Consumer Secret as well as a Consumer
19

20
00:01:23,340 --> 00:01:25,320
Key is the second one.
20

21
00:01:25,380 --> 00:01:30,480
So I'm just gonna go ahead and copy this line of code.
21

22
00:01:30,480 --> 00:01:34,870
And we're going to go ahead and paste it just under our IBOutlets.
22

23
00:01:34,890 --> 00:01:43,050
Now, I have to add a "let" here so that we create a new constant code swifter and it's going to be initialized
23

24
00:01:43,260 --> 00:01:45,900
using a consumerKey and consumerSecret.
24

25
00:01:46,260 --> 00:01:53,470
So we have to replace these two placeholders with our actual values from the Twitter app.
25

26
00:01:53,470 --> 00:01:59,610
So if you head over to your Twitter Application Manager, remember, this is under apps.twitter.com.
26

27
00:01:59,610 --> 00:02:06,480
And there you have to log in into the account that you used to set up your Twitter application and then
27

28
00:02:06,570 --> 00:02:12,690
following what we did before going to Keys and Access Tokens, you should be able to have a Consumer Key,
28

29
00:02:12,690 --> 00:02:17,550
this is your API Key which you are going to paste in here as a String,
29

30
00:02:17,550 --> 00:02:24,930
so remember to enclose it inside some quotation marks, and also make sure there's no spaces between the
30

31
00:02:24,930 --> 00:02:28,160
beginning and the end and the quotation marks.
31

32
00:02:28,200 --> 00:02:32,580
And secondly, we're going to copy our Consumer Secret.
32

33
00:02:32,580 --> 00:02:34,280
Now, notice, it's actually quite long,
33

34
00:02:34,290 --> 00:02:35,400
so just double click,
34

35
00:02:35,400 --> 00:02:40,110
and we're going to copy it over here, again, inside some quotation marks.
35

36
00:02:40,650 --> 00:02:49,170
So, now this line of code will use Swifter to initialize a new instance of this framework
36

37
00:02:49,170 --> 00:02:57,010
and it's going to authenticate ourselves with the Twitter servers using our API Key and API Secret.
37

38
00:02:57,030 --> 00:03:04,320
Now, at this stage, and previously, some of you guys might have wondered, "Well, if we have our API Keys inside
38

39
00:03:04,320 --> 00:03:07,840
here and we upload our app to GitHub,
39

40
00:03:07,920 --> 00:03:09,410
isn't that kind of dangerous?
40

41
00:03:09,420 --> 00:03:11,060
And you're absolutely right.
41

42
00:03:11,070 --> 00:03:14,520
Having API Keys, especially ones you have to pay for,
42

43
00:03:14,820 --> 00:03:21,090
so, for example, currently on the Twitter app, this is using standard access, so we're not paying and we're
43

44
00:03:21,090 --> 00:03:27,570
not giving any of our payment details so that international students who have issues using credit cards
44

45
00:03:27,600 --> 00:03:34,080
in the US or don't actually have a credit card, then you know you can still learn along with all of the
45

46
00:03:34,080 --> 00:03:34,620
lessons.
46

47
00:03:34,650 --> 00:03:40,910
So I try to avoid using any services in my tutorial that requires a credit card sign up.
47

48
00:03:41,130 --> 00:03:48,030
But at some point, you might need to use a higher access level tier, such as their Premium tier where
48

49
00:03:48,030 --> 00:03:54,360
you can make more queries to their servers per minute, and you can get back more data from the Ywitter
49

50
00:03:54,360 --> 00:03:55,650
servers as well.
50

51
00:03:55,650 --> 00:04:02,500
So at that stage, then your API Key and your API Secret is directly linked to your credit card,
51

52
00:04:02,520 --> 00:04:08,190
so that means that if somebody steals it and they use it in their app and they use up all of your credits,
52

53
00:04:08,700 --> 00:04:10,770
then you're not going to be very happy.
53

54
00:04:10,770 --> 00:04:18,140
So in those cases, you have to make sure that these API Keys are not uploaded to GitHub.
54

55
00:04:18,180 --> 00:04:24,360
There are a lot of people who crawl through GitHub projects looking for these API Keys and using them,
55

56
00:04:24,420 --> 00:04:26,670
especially things like AWS Keys,
56

57
00:04:26,670 --> 00:04:31,920
it's very, very precious, and you have to make sure that you keep this secret.
57

58
00:04:31,920 --> 00:04:38,700
Now, the simplest way of doing that is to simply create a new plist file by going to File, New, File,
58

59
00:04:39,890 --> 00:04:46,550
and under the iOS tab, we create a new Property List file.
59

60
00:04:49,640 --> 00:04:57,270
And the Secrets.plist can have your API Key, so this will be API Key,
60

61
00:04:57,310 --> 00:05:02,680
and then you put in the String value, obviously, here, and then you add another one
61

62
00:05:02,680 --> 00:05:05,410
that's the API Secret,
62

63
00:05:05,410 --> 00:05:07,870
and then you add the string value here.
63

64
00:05:07,870 --> 00:05:16,120
And as we described inside the GitHub module, you would add this Secrets.plist to the gitignore
64

65
00:05:16,120 --> 00:05:20,330
plist so that it does not get uploaded to GitHub.
65

66
00:05:20,350 --> 00:05:28,150
And this is probably one of the most frequently used ways for iOS developers to obfuscate their secrets
66

67
00:05:28,150 --> 00:05:30,880
such as API Keys and API Secrets.
67

68
00:05:30,880 --> 00:05:38,530
Now, some of you might be wondering, "Once my app is on the app store and somebody gets a hold of the actual
68

69
00:05:38,590 --> 00:05:45,310
IPA file or the actual app software and they download it, and they try to butcher it, and they try to
69

70
00:05:45,310 --> 00:05:49,010
dissect it, will they be able to find my API key?
70

71
00:05:49,030 --> 00:05:51,490
Yes, that is--that is in fact the case.
71

72
00:05:51,580 --> 00:05:58,960
And in the course resources list, I linked to a Stack Overflow, and so that's really quite exhaustive
72

73
00:05:59,050 --> 00:06:01,680
on this topic.
73

74
00:06:01,720 --> 00:06:08,560
In fact, you'll find that it's actually very, very difficult to keep your secure keys completely secure
74

75
00:06:08,620 --> 00:06:14,800
if you have an iOS app just because people are able to download the app and you need the keys to be accessible
75

76
00:06:15,220 --> 00:06:17,360
at the stage when the app is run.
76

77
00:06:17,440 --> 00:06:22,170
So this is a good link to have a read about if you are really worried about this topic.
77

78
00:06:22,330 --> 00:06:29,960
But in most cases, it's sufficient to simply use a Secrets.plist file and keep it off GitHub.
78

79
00:06:29,960 --> 00:06:30,160
All right.
79

80
00:06:30,160 --> 00:06:39,970
So now that we've got our Swifter Authentication setup, the next thing to do is to use Swifter and to search
80

81
00:06:40,030 --> 00:06:42,130
for tweets on Twitter.
81

82
00:06:42,130 --> 00:06:49,360
Now, unfortunately, if you have a look at the documentation for Swifter, it's not very exhaustive.
82

83
00:06:49,450 --> 00:06:56,170
It tells you about how you get the Home Timeline and how you can getUser FollowerIDs, getListSubscribers,
83

84
00:06:56,590 --> 00:07:03,250
but there's actually a lot more methods that it can do and they're not all listed over here.
84

85
00:07:03,730 --> 00:07:06,320
So how can we figure out what it can do?
85

86
00:07:07,180 --> 00:07:08,760
Well, if we go inside
86

87
00:07:08,760 --> 00:07:14,320
viewDidLoad and we tap into our Swifter object and we hit dot.
87

88
00:07:14,350 --> 00:07:20,630
Now, we can access all of the methods that are available and automatically suggested to us that Swifter
88

89
00:07:20,710 --> 00:07:22,170
can perform.
89

90
00:07:22,210 --> 00:07:30,340
So if we scroll through this list, you can see we've got addListMember, authorize, blockUser, 
90

91
00:07:30,340 --> 00:07:38,170
checkListMembership, createList, deleteList, destroyDirectMessages, favoriteTweet, followUser. And you can
91

92
00:07:38,170 --> 00:07:41,190
see that these methods are pretty self-explanatory.
92

93
00:07:41,200 --> 00:07:46,030
They're very well named and you should be able to understand exactly what it does
93

94
00:07:46,120 --> 00:07:50,790
just by reading the method name which is always a good sign of good naming conventions,
94

95
00:07:50,800 --> 00:07:51,080
right?
95

96
00:07:51,430 --> 00:07:58,030
So remember that when your naming your own method to follow this kind of style where it should be really
96

97
00:07:58,030 --> 00:08:03,190
obvious to anybody reading it even without any documentation what the method does.
97

98
00:08:03,280 --> 00:08:08,710
Now, in our case, the method that we need--this is a very long list because we can use Swifter to do a
98

99
00:08:08,710 --> 00:08:17,140
lot of things, such as get the IDs of the followers of the user, getUserSuggestions, listTweets,
99

100
00:08:17,140 --> 00:08:26,230
lookupFriendships, loads and loads of things. But the one that we want is something called searchTweet.
100

101
00:08:26,230 --> 00:08:34,450
So if we scroll down to this area around the "S" level, you can see that we've got searchTweet using a
101

102
00:08:34,450 --> 00:08:41,560
String and giving a failure handler or we can have the really exhaustive one which is searchTweet using
102

103
00:08:41,620 --> 00:08:44,870
loads of things. And that's the one that I'm going to choose.
103

104
00:08:45,640 --> 00:08:53,090
So let's go ahead and hit enter to get it to automatically insert this gigantic method call.
104

105
00:08:53,260 --> 00:08:59,230
Now, don't worry about how many parameters this method call has because we're not gonna be using many
105

106
00:08:59,230 --> 00:09:03,070
of them and we'll get rid of some of the ones that we don't need.
106

107
00:09:03,070 --> 00:09:09,490
Now, as you know from before, when you hold down the option key and your question mark comes up, when you
107

108
00:09:09,490 --> 00:09:12,630
hover over, say, a method or an object.
108

109
00:09:12,700 --> 00:09:20,260
So for the object, I can click on it and I can see what is its type or what is its class, essentially.
109

110
00:09:20,260 --> 00:09:27,910
And for the methods, I can click on it and it gives me the Declaration, the Summary, as well as a Discussion,
110

111
00:09:28,030 --> 00:09:31,920
and all of the Parameters that are available.
111

112
00:09:31,930 --> 00:09:35,980
Now, this Discussion part actually comes from the Twitter APIs.
112

113
00:09:36,490 --> 00:09:43,420
So if you have a look on the Twitter Developer docs, again, this is a link inside the Course Resources
113

114
00:09:43,420 --> 00:09:46,210
list so that you can navigate to it easily.
114

115
00:09:46,210 --> 00:09:51,620
You can see that there's a section called Standard Search API which is what we have access to by not
115

116
00:09:51,620 --> 00:09:53,670
paying Twitter anything.
116

117
00:09:53,750 --> 00:10:02,610
And here, you can see that there is a detailed reference of the Search API endpoints.
117

118
00:10:02,690 --> 00:10:10,300
So let's head over there. And here is a whole bunch of information of, essentially, how this method works,
118

119
00:10:10,310 --> 00:10:16,430
and this is where this part comes from. As you can see here, "Returns a collection of relevant Tweets matching
119

120
00:10:16,430 --> 00:10:21,650
a specified query, "Returns a collection of relevant Tweets matching a specific query."
120

121
00:10:21,680 --> 00:10:28,610
So this is the page that we're going to be referring to when we are using this particular Swifter method.
121

122
00:10:28,610 --> 00:10:34,760
Now, if you look at all of these parameters and you're wondering what each of them do, then have no fear,
122

123
00:10:34,820 --> 00:10:41,840
because they are all listed in a really neat table and they're all explained extensively about what
123

124
00:10:41,840 --> 00:10:46,040
they are for, how you use it, what they are expecting.
124

125
00:10:46,040 --> 00:10:48,350
So let's go through some of these options.
125

126
00:10:48,410 --> 00:10:56,180
The only parameters that are required is the one that is using which is "searchTweet using:"
126

127
00:10:56,180 --> 00:10:58,510
So this is your query String, right?
127

128
00:10:58,520 --> 00:11:04,060
So if you wanted to search for tweets that were at Apple, then that's what you would put in here.
128

129
00:11:04,060 --> 00:11:08,170
Effectively, you would replace the placeholder with a String
129

130
00:11:08,180 --> 00:11:10,190
that's @Apple,
130

131
00:11:10,190 --> 00:11:15,430
then you'll be searching for tweets that contain this handle.
131

132
00:11:15,440 --> 00:11:17,030
So this is your search query.
132

133
00:11:17,030 --> 00:11:20,660
And, of course, if you're going to search for tweets, this has to exist.
133

134
00:11:20,660 --> 00:11:22,400
So this is obligatory.
134

135
00:11:22,460 --> 00:11:27,980
The other two that you need to have in there is what to do when you get a successful response and what
135

136
00:11:27,980 --> 00:11:34,370
to do when you get a failure response back from the Twitter service. You need to handle those. And all
136

137
00:11:34,370 --> 00:11:36,470
of the rest of these other ones,
137

138
00:11:36,500 --> 00:11:43,730
these other parameters, they're all optional. And you can see that because they list it in this table here.
138

139
00:11:44,090 --> 00:11:50,600
You can see whether if it's required, this is column, and the search query is, of course, required. Geocode
139

140
00:11:50,630 --> 00:11:54,260
is optional. Language is optional. Locale is optional.
140

141
00:11:54,260 --> 00:11:55,840
All of these are optional,
141

142
00:11:55,880 --> 00:12:04,880
other than this parameter using, which is the same as the q parameter over here, and the other one is
142

143
00:12:04,880 --> 00:12:06,040
success and failure.
143

144
00:12:06,380 --> 00:12:13,580
So let's go ahead and delete all of these other parameters and only keep what is strictly necessary.
144

145
00:12:13,980 --> 00:12:14,290
Okay.
145

146
00:12:14,300 --> 00:12:21,230
So next thing we need to handle is what to do when the search was successful and we get a successful
146

147
00:12:21,230 --> 00:12:23,690
response from the Twitter servers.
147

148
00:12:24,050 --> 00:12:31,280
Well, if you click on this particular placeholder, make it turn blue, and hit enter, and it automatically
148

149
00:12:31,280 --> 00:12:34,220
insert our callback closure over here.
149

150
00:12:34,790 --> 00:12:41,570
And these are the two objects that we're going to get back upon a successful query. And the first object
150

151
00:12:41,930 --> 00:12:46,520
is the actual set of results of tweets.
151

152
00:12:46,520 --> 00:12:51,680
And the second object is the metadata around our search.
152

153
00:12:51,680 --> 00:12:53,840
So how long did the search take?
153

154
00:12:53,840 --> 00:12:55,820
Was it successful, et cetera?
154

155
00:12:55,850 --> 00:13:03,800
So we're gonna name these two JSONs, results and metadata. And then inside this part for the code 
155

156
00:13:03,800 --> 00:13:12,890
placeholder is where we're going to print out our results, just so that we can test it and see that everything's
156

157
00:13:12,890 --> 00:13:17,720
working as expected. The next one is to handle the failure scenario.
157

158
00:13:17,780 --> 00:13:25,640
So let's click on the Swifter FailureHandler and, again, hit enter to automatically insert the callback.
158

159
00:13:26,180 --> 00:13:26,920
And the error,
159

160
00:13:26,930 --> 00:13:33,860
we're just gonna call error. And inside the code placeholder, I'm going to delete that and, instead, replace
160

161
00:13:33,860 --> 00:13:46,720
it with print and we're going to say, "There was an error with the Twitter API Request,"
161

162
00:13:46,750 --> 00:13:52,130
and then we're going to include that error in there.
162

163
00:13:53,550 --> 00:13:59,700
So if there was an error with making a request to the Twitter servers, for example, if we had our consumerKey
163

164
00:13:59,700 --> 00:14:06,300
wrong or we didn't include a consumerKey and consumerSecret, then our authentication would fail, and
164

165
00:14:06,300 --> 00:14:12,210
we would get an error back from the Twitter servers saying something like, 4 or 3, not authenticated, and
165

166
00:14:12,210 --> 00:14:18,760
we'll get this printed down here in our debug console, and we can use it to figure out what went wrong.
166

167
00:14:18,780 --> 00:14:24,450
Now, if it was successful, however, we would be inside this area printing the results that we got back
167

168
00:14:24,780 --> 00:14:27,590
that matches our particular search query,
168

169
00:14:27,620 --> 00:14:32,200
so all the tweets that contain the handle at Apple.
169

170
00:14:32,220 --> 00:14:39,090
So, now this is the very simplest way of searching for tweets through the Twitter API.
170

171
00:14:39,090 --> 00:14:46,110
So let's give this a go and I'm just gonna go ahead and click Run so that when our View Controller, our
171

172
00:14:46,110 --> 00:14:51,290
initial View Controller gets loaded up, then all of this code gets carried out,
172

173
00:14:51,390 --> 00:14:58,200
and we should be able to see either a set of JSON results or a error in our debug console.
173

174
00:15:01,620 --> 00:15:01,880
All right.
174

175
00:15:01,910 --> 00:15:03,260
So there goes our app.
175

176
00:15:03,330 --> 00:15:10,140
It currently doesn't do anything. But if we look in our debug console, you can see there's loads and loads
176

177
00:15:10,140 --> 00:15:15,360
of information that came back. So we can presume that it was pretty successful because if there was an
177

178
00:15:15,360 --> 00:15:18,100
error, it would be much shorter than this.
178

179
00:15:18,120 --> 00:15:24,010
So let's go ahead and click in here and hit command A to select all, and then command C to copy all of
179

180
00:15:24,010 --> 00:15:24,490
it.
180

181
00:15:24,780 --> 00:15:31,980
And we're going to go on to a Chrome and we're going to find ourselves a JSON editor. So I'm gonna go
181

182
00:15:31,980 --> 00:15:41,160
over to jsoneditoronline.org, and I'm going to paste everything that I had from my debug console.
182

183
00:15:41,160 --> 00:15:46,680
Now, remember that there's a part of the debug console that has all of these messages from Xcode. And
183

184
00:15:46,680 --> 00:15:49,410
this is, of course, not a part of the JSON.
184

185
00:15:49,470 --> 00:15:56,820
And so we're going to delete all of those parts. And starting at that square bracket and ending at a
185

186
00:15:56,820 --> 00:16:01,590
closing square bracket, should be everything that is our JSON.
186

187
00:16:01,590 --> 00:16:08,760
So let's go ahead and click the right arrow to turn it into a format that is much more human readable.
187

188
00:16:09,270 --> 00:16:15,080
And you can see that we've got an array of 15 items back from the Twitter server.
188

189
00:16:15,270 --> 00:16:23,780
And if we check the first item, you can see it's got a whole bunch of properties such as the source.
189

190
00:16:23,790 --> 00:16:28,350
So this is, what was the application that was used to make this tweet,
190

191
00:16:28,500 --> 00:16:35,130
what was the date that it was created at, what was the location that it was created at, was it--
191

192
00:16:35,130 --> 00:16:37,290
was it favorited or not,
192

193
00:16:37,290 --> 00:16:40,750
what was the text of the actual tweet,
193

194
00:16:40,800 --> 00:16:44,220
how many times has it been retweeted,
194

195
00:16:44,310 --> 00:16:46,830
what's the language it's in,
195

196
00:16:46,830 --> 00:16:47,760
was it in reply,
196

197
00:16:47,760 --> 00:16:53,900
and you can see there's like loads and loads of pieces of data that's associated with this single tweet.
197

198
00:16:54,000 --> 00:16:59,100
But the part that we're interested in is actually just the text of the tweet because that's what we're
198

199
00:16:59,100 --> 00:17:03,120
going to be using to perform sentiment analysis on.
199

200
00:17:03,120 --> 00:17:08,640
So that's what we'll be trying to retrieve from our JSON once we get it up and running.
