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.