Hi! all!! we’re back!!, some time ago i introduced you VendorKit, now is time for CocoaPods also a dependency management tool and what i can tell you about it is: i’ve already tested and is easy, is fast and works like a charm!.
In this tutorial you’ll learn how to use CocoaPods in your iOS project by doing a simple twitter search app, and CocoaPods will handle all of your dependencies.
Let’s Code!.
Roadmap
In this tutorial we’re going to cover each of these steps:
Setup CocoaPods.
Setup RestKit library.
Fetch tweets using the Twitter Search WebService.
Setup custom UITableViewCell.
CocoaPods
CocoaPods manages library dependencies for your Xcode project. You specify the dependencies for your project in one easy text file. CocoaPods resolves dependencies between libraries, fetches source code for the dependencies, and creates and maintains an Xcode workspace to build your project.
Installing CocoaPods
CocoaPods is distributed as a ruby gem, installing it is as easy as running the following commands in the terminal:
$ [sudo] gem install cocoapods
$ pod setup
Now that we’ve got CocoaPods installed it’s time to get started
Getting Started
First download the starting project from here, it’s a single view application with a UISearchBar and UITableView already set up, compile and run your project you should see something like this:
take a look at the implementation of the ViewController class, this class already handle a few things for us, like resizing the table when the keyboard shows up, when the user taps the search button the keyboard hides, all IBOutles needed are already set up.
I know there’s a lot of things already made, but this tutorial is not focus on how to set up the UI, if you want to learn how to set up the MainStoryboard with the the UISearchBar and UITableView, take a look at these tutorials:
First close the Xcode project, next open terminal, and navigate to the folder where your project is. Type the following:
$touch Podfile
open the pod file with your favorite text editor and then copy and paste the following:
platform :ios
pod 'RestKit', '0.10.1'
In the above lines, first you set the platform to iOS and then you’ve declared your first dependency, RestKit v0.10.1.
Now, save and close the file, go back to terminal, and type the following command to install the dependencies in your project:
$ pod install
you should see output similar to the following:
Updating spec repo `master'
Installing FileMD5Hash (0.0.1)
Installing ISO8601DateFormatter (0.6)
Installing JSONKit (1.5pre)
Installing LibComponentLogging-Core (1.1.6)
Installing LibComponentLogging-NSLog (1.0.4)
Installing NSData+Base64 (1.0.0)
Installing RestKit/JSON (0.10.1)
Installing SOCKit (1.0)
Installing cocoa-oauth (0.0.1)
Generating support files
[!] From now on use `TwitterSearch.xcworkspace'.
-> Integrating `libPods.a' into target `TwitterSearch' of Xcode project `TwitterSearch.xcodeproj'.
from now remember to always open the Xcode workspace instead of the project file when you’re building.
$ open TwitterSearch.xcworkspace
installing RestKit for the first time in your project could take a while, there’s a lot of things behind Restkit, so be patient.
now your Xcode workspace should look like the following image:
your workspace now have two projects just remember that we’re working on the TwitterSearch project.
go to the ViewController.h and include the following header.
1
#import <RestKit/RestKit.h>
Click Run. If it builds without error, RestKit is now working!!!!
really cool, huh!
To see all the hassle that you’ve avoided, take a look at all the steps that you need to do to install Restkit manually.
Fetching your first tweets
We are going to call the Search WebService from twitter to fetch our tweets, you can take a look at this example, the service response may look like the following:
{"completed_in":0.119,"max_id":223562723684913150,"max_id_str":"223562723684913155","next_page":"?page=2&max_id=223562723684913155&q=iOS%205&rpp=5&result_type=recent","page":1,"query":"iOS+5","refresh_url":"?since_id=223562723684913155&q=iOS%205&result_type=recent","results":[{"created_at":"Thu, 12 Jul 2012 23:41:21 +0000","from_user":"iTwad","from_user_id":159434131,"from_user_id_str":"159434131","from_user_name":"iJD","geo":null,"id":223562723684913150,"id_str":"223562723684913155","iso_language_code":"en","metadata":{"result_type":"recent"},"profile_image_url":"http://a0.twimg.com/sticky/default_profile_images/default_profile_3_normal.png","profile_image_url_https":"https://si0.twimg.com/sticky/default_profile_images/default_profile_3_normal.png","source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>","text":"Jailbreak: iPhone 4/4S/3Gs iOS-5.1.1 Issue Fixed - Unlock iPhone 4/4S/3Gs App ... - The Beacon Herald: The Beaco... http://t.co/XFjCM2j6","to_user":null,"to_user_id":0,"to_user_id_str":"0","to_user_name":null},{"created_at":"Thu, 12 Jul 2012 23:40:21 +0000","from_user":"lin_kz","from_user_id":197484898,"from_user_id_str":"197484898","from_user_name":"lin_kz","geo":null,"id":223562472752295940,"id_str":"223562472752295938","iso_language_code":"de","metadata":{"result_type":"recent"},"profile_image_url":"http://a0.twimg.com/profile_images/1643479712/image_normal.jpg","profile_image_url_https":"https://si0.twimg.com/profile_images/1643479712/image_normal.jpg","source":"<a href="http://www.hootsuite.com" rel="nofollow">HootSuite</a>","text":"RT @unlockboot: Unlock iPhone 4 on iOS 5.1.1 Baseband 4.12.01 With Safera1n is Scam http://t.co/nyEATK9i","to_user":null,"to_user_id":0,"to_user_id_str":"0","to_user_name":null},{"created_at":"Thu, 12 Jul 2012 23:37:32 +0000","from_user":"ebookschreiber","from_user_id":350806797,"from_user_id_str":"350806797","from_user_name":"ebookschreiber","geo":null,"id":223561761972944900,"id_str":"223561761972944897","iso_language_code":"de","metadata":{"result_type":"recent"},"profile_image_url":"http://a0.twimg.com/profile_images/1484294015/ebookscheiber_normal.jpg","profile_image_url_https":"https://si0.twimg.com/profile_images/1484294015/ebookscheiber_normal.jpg","source":"<a href="http://dlvr.it" rel="nofollow">dlvr.it</a>","text":"Sie sind da: iOS 5, iTunes 10.5 und iCloud http://t.co/9LeAyKJ5","to_user":null,"to_user_id":0,"to_user_id_str":"0","to_user_name":null},{"created_at":"Thu, 12 Jul 2012 23:37:29 +0000","from_user":"Kindle_eReader","from_user_id":40649488,"from_user_id_str":"40649488","from_user_name":"FreshTech","geo":null,"id":223561749968850940,"id_str":"223561749968850944","iso_language_code":"de","metadata":{"result_type":"recent"},"profile_image_url":"http://a0.twimg.com/profile_images/854338956/kindle_normal.jpg","profile_image_url_https":"https://si0.twimg.com/profile_images/854338956/kindle_normal.jpg","source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>","text":"Jailbreak: iPhone 4/4S/3Gs iOS-5.1.1 Issue Fixed - Unlock iPhone 4/4S/3Gs App ... - The Beacon Herald http://t.co/TXlEB6RA","to_user":null,"to_user_id":0,"to_user_id_str":"0","to_user_name":null},{"created_at":"Thu, 12 Jul 2012 23:33:22 +0000","from_user":"Electronics_bot","from_user_id":207897530,"from_user_id_str":"207897530","from_user_name":"전자제품 봇","geo":null,"id":223560713917046800,"id_str":"223560713917046784","iso_language_code":"ko","metadata":{"result_type":"recent"},"profile_image_url":"http://a0.twimg.com/profile_images/1152738552/images_normal.jpeg","profile_image_url_https":"https://si0.twimg.com/profile_images/1152738552/images_normal.jpeg","source":"<a href="http://twittbot.net/" rel="nofollow">twittbot.net</a>","text":"순순히 iOS 5 업뎃을 해주시면 유혈사태는 일어나지 않을 것입니다","to_user":null,"to_user_id":0,"to_user_id_str":"0","to_user_name":null}],"results_per_page":5,"since_id":0,"since_id_str":"0"}
The JSON output above lists 5 tweets. The first thing that we need to do is to define our data model class based on the JSON output, right now, we just need to map the from_user field from the JSON tweet data. So, create a new objective-c class and name it Tweet.
open Tweet.h and replace the contents of the file with the following code:
go to the ViewController.h and include the following header.
1
#import "Tweet.h"
next add the following code in the viewDidLoad method after section #1:
123456789101112
// 2 - set up the base URLRKURL*baseURL=[RKURLURLWithBaseURLString:@"http://search.twitter.com/"];RKObjectManager*objectManager=[RKObjectManagerobjectManagerWithBaseURL:baseURL];objectManager.client.baseURL=baseURL;// 3 - map Tweet class with the JSON responseRKObjectMapping*tweetMapping=[RKObjectMappingmappingForClass:[Tweetclass]];[tweetMappingmapKeyPathsToAttributes:@"from_user",@"from_user",nil];[objectManager.mappingProvidersetMapping:tweetMappingforKeyPath:@"results"];// 4 - send search request![selfsearchRequest];
The first thing that we need to do is to define the baseURL for the TwitterSearch API, all the send request will be appended to this baseURL. Next we use the RKObjectMapping to map the properties from the JSON data to our data model class, mapKeyPathsToAttributes will map the JSON fields to your data model’s attributes.
now let’s implement the searchRequest method, copy the following code before the viewDidLoad method:
12345678910111213141516
-(void)searchRequest{// 1 - set up search params!NSString*q=@"iOS 5";NSString*rpp=@"5";NSString*with_twitter_user_id=@"true";NSString*result_type=@"recent";// 2 - map params in to a NSDictionaryNSDictionary*queryParams;queryParams=[NSDictionarydictionaryWithObjectsAndKeys:q,@"q",rpp,@"rpp",with_twitter_user_id,@"with_twitter_user_id",result_type,@"result_type",nil];// 3 - send requestRKObjectManager*objectManager=[RKObjectManagersharedManager];RKURL*URL=[RKURLURLWithBaseURL:[objectManagerbaseURL]resourcePath:@"/search.json"queryParameters:queryParams];[objectManagerloadObjectsAtResourcePath:[NSStringstringWithFormat:@"%@?%@",[URLresourcePath],[URLquery]]delegate:self];NSLog(@"resource path: %@",[NSStringstringWithFormat:@"%@?%@",[URLresourcePath],[URLquery]]);}
The searchRequest method is very self explanatory, first we declare all the query params that we’re going to need to make the search call, and then we make the call based on the baseURL adding all of these query params.
RestKit will send back responses using delegate methods. To receive those responses, we must adopt the RKObjectLoaderDelegate protocol. To do this, add this to your interface declaration in ViewController.h:
Then in ViewController.m, add the following RKObjectLoaderDelegate methods:
123456789101112131415161718192021222324
#pragma mark -#pragma mark RKObjectLoaderDelegate implementation-(void)objectLoader:(RKObjectLoader*)objectLoaderdidFailWithError:(NSError*)error{NSLog(@"Error: %@",[errorlocalizedDescription]);// 1 - display error messageUIAlertView*alert=[[UIAlertViewalloc]initWithTitle:@"Error"message:@"Error retrieving Tweets"delegate:selfcancelButtonTitle:@"Cancel"otherButtonTitles:@"Ok",nil];[alertshow];}-(void)request:(RKRequest*)requestdidLoadResponse:(RKResponse*)response{NSLog(@"response code: %d",[responsestatusCode]);}-(void)objectLoader:(RKObjectLoader*)objectLoaderdidLoadObjects:(NSArray*)objects{NSLog(@"objects[%d]",[objectscount]);[tweetsremoveAllObjects];for(Tweet*tinobjects){[tweetsaddObject:t];}[self.tableViewreloadData];}
The only required method is objectLoader:didFailWithError, but we also need objectLoader:didLoadObjects to retrieve our request data. It returns an array of Tweet objects based on the object mapping you registered in viewDidLoad.
now change this:
12345678910111213141516171819202122
#pragma mark -#pragma mark UITableViewDelegate, UITableViewDataSource protocols implementations-(NSInteger)tableView:(UITableView*)tableViewnumberOfRowsInSection:(NSInteger)section{return15;}-(UITableViewCell*)tableView:(UITableView*)tableViewcellForRowAtIndexPath:(NSIndexPath*)indexPath{// 1 - set up cell idstaticNSString*CellIdentifier=@"Cell";// 2 - setup custom cellUITableViewCell*cell=(UITableViewCell*)[tableViewdequeueReusableCellWithIdentifier:CellIdentifier];if(cell==nil){cell=[[UITableViewCellalloc]initWithStyle:UITableViewCellStyleSubtitlereuseIdentifier:CellIdentifier];}cell.textLabel.text=@"Detail";returncell;}
to this:
12345678910111213141516171819202122232425
#pragma mark -#pragma mark UITableViewDelegate, UITableViewDataSource protocols implementations-(NSInteger)tableView:(UITableView*)tableViewnumberOfRowsInSection:(NSInteger)section{return[tweetscount];}-(UITableViewCell*)tableView:(UITableView*)tableViewcellForRowAtIndexPath:(NSIndexPath*)indexPath{// 1 - set up cell idstaticNSString*CellIdentifier=@"Cell";// 2 - setup custom cellUITableViewCell*cell=(UITableViewCell*)[tableViewdequeueReusableCellWithIdentifier:CellIdentifier];if(cell==nil){cell=[[UITableViewCellalloc]initWithStyle:UITableViewCellStyleSubtitlereuseIdentifier:CellIdentifier];}// 3 - start filling all labels!Tweet*tweet=[tweetsobjectAtIndex:indexPath.row];cell.textLabel.text=[NSStringstringWithFormat:@"@%@",tweet.from_user];returncell;}
The only changes here, is how we’re filling cell labels, also numberOfRowsInSection method now returns the number of Tweets based on the data source, all the rest keeps the same.
Finally let’s add the NSMutableArray that will hold our Tweet data.
switch to the interface declaration ViewController.h and add the following property:
1
@property(strong,nonatomic)NSMutableArray*tweets;
In ViewController.m, synthesize the property:
1
@synthesizetweets;
and don’t forget to allocate your tweets array!, add the following line just before section 2 in the viewDidLoad method:
123456
tweets=[[NSMutableArrayalloc]init];// 2 - set up the base URL....
if everything went well, when you run the project you should see something like the following screen:
Having trouble? if you get stuck somewhere, download the working project from here!
Customizing TableViewCells
Right now, the TableViewCells it’s very raw, it only contains the user name. let’s change that!
first create a new objective-c class inherit from UITableViewCell and name it TweetCell.
go to the TweetCell.h and replace the contents of the file whit the following code:
Later, we are going to connect all IBOutlets with our custom cell view.
In MainStoryboard, select the table view, click the size inspector ( ⌥ ⌘ 5), change the Row Height from 44 to 70.
now select the table view cell, in the size inspector ( ⌥ ⌘ 5), change the Row Height to Custom and from 44 to 70.
in the attributes inspector ( ⌥ ⌘ 4) change the Style to Custom, set the cell identifier to TweetCell.
now go to the identity inspector ( ⌥ ⌘ 3) and set the Class from UITableViewCell to TweetCell.
now add 4 UILabels and 1 UIImage in to the table view cell, like this:
and set the following properties to the UI:
UIImage View Size: 48w 48h Position: 10x 8y
UILabel user name Font: System Bold 12.0 AutoShrink: disabled Size: 67w 21h Position: 61x 6y
UILabel @user: Font: System 11.0 Color: Dark Gray Color Size: 109w 21h Position 176x 3y
UILabel time Font: System 11.0 Alignment: left Size: 68w 21h Position: 246x 3y.
UILabel text Font: System 13.0 Lines: 0 Size: 250w 42h Position: 61x 20y.
Now connect all the outlets in TweetCell. In the connections inspector, connect the outlets: usernameLabel, userLabel, timeLabel and textLabel to their respective UILabels, and don’t forget the userImageView!.
Add an import for TweetCell at ViewController.h:
1
#import "TweetCell.h"
now switch to the implementation file ViewController.h and change this:
123456789101112131415161718
-(UITableViewCell*)tableView:(UITableView*)tableViewcellForRowAtIndexPath:(NSIndexPath*)indexPath{// 1 - set up cell idstaticNSString*CellIdentifier=@"Cell";// 2 - setup custom cellUITableViewCell*cell=(UITableViewCell*)[tableViewdequeueReusableCellWithIdentifier:CellIdentifier];if(cell==nil){cell=[[UITableViewCellalloc]initWithStyle:UITableViewCellStyleSubtitlereuseIdentifier:CellIdentifier];}// 3 - start filling all labels!Tweet*tweet=[tweetsobjectAtIndex:indexPath.row];cell.textLabel.text=[NSStringstringWithFormat:@"@%@",tweet.from_user];returncell;}
to:
123456789101112131415161718192021
-(UITableViewCell*)tableView:(UITableView*)tableViewcellForRowAtIndexPath:(NSIndexPath*)indexPath{// 1 - set up cell idstaticNSString*CellIdentifier=@"TweetCell";// 2 - setup custom cellTweetCell*cell=(TweetCell*)[tableViewdequeueReusableCellWithIdentifier:CellIdentifier];if(cell==nil){cell=[[TweetCellalloc]initWithStyle:UITableViewCellStyleSubtitlereuseIdentifier:CellIdentifier];}// 3 - start filling all labels!Tweet*tweet=[tweetsobjectAtIndex:indexPath.row];cell.usernameLabel.text=tweet.from_user;cell.userLabel.text=[NSStringstringWithFormat:@"@%@",tweet.from_user];cell.timeLabel.text=tweet.created_at;cell.textLabel.text=tweet.text;returncell;}
this wont work if you try to build and run, because Tweet doesn’t have the rest of the properties. So let’s update our Tweet data model.
go to the Tweet.h and add the following properties:
now in the ViewController.m, update the step three (tweetMapping) in the viewDidLoad method to:
123456789
// 3 - map Tweet class with the JSON responseRKObjectMapping*tweetMapping=[RKObjectMappingmappingForClass:[Tweetclass]];[tweetMappingmapKeyPathsToAttributes:@"created_at",@"created_at",@"from_user",@"from_user",@"from_user_name",@"from_user_name",@"profile_image_url",@"profile_image_url",@"text",@"text",@"id_str",@"id_str",nil];[objectManager.mappingProvidersetMapping:tweetMappingforKeyPath:@"results"];
Build and run, and you should see something like this:
Having trouble? if you get stuck somewhere, download the working project from here!
Now you’ve the app talking to Twitter Search WebService and you’ve already set up your custom TableView Cell, you can play around a bit with sending data over and maybe adjusting the query params. But, you’re far from finished! So stay tuned for Part 2 of this tutorial, where you’ll load more cool libraries using CocoaPods and make an even better app.