Introduction to CocoaPods

Marcelo Fabri Marcelo Fabri

This post is also available in: Russian

Make an app with several library dependencies - without the pain!

Make an app with several library dependencies - without the pain!

This is a post by iOS Tutorial Team Member Marcelo Fabri, an iOS developer working at Movile. Check out his personal website or find him on Twitter or on .

In this tutorial, you’ll learn how to use a popular dependency management tool called CocoaPods.

But wait! What is a dependency management tool and why do you need one?

As an iOS developer, you certainly use a lot of code made by others, in the shape of libraries. You may not remember, but how complicated would your life be if you had to implement everything from scratch?

Usually (since building static libraries manually is sooooo boring), you just add the library code into your project. But that has some disadvantages:

  • Code that could be somewhere else is stored in your repository, wasting space.
  • Sometimes, it’s hard to get a specific version of a library.
  • There’s no central place where you can see which libraries are available.
  • Finding a new version of a library and updating your project with it is boring and sometimes, painful.
  • Downloading libraries manually creates a tendency to perhaps make some changes to the downloaded code and just leaving it there (making updating harder, as you’ll need to merge the changes you made with the code you download for the next version).

A dependency management tool helps you overcome most of the issues mentioned above. It will resolve dependencies between the various libraries you use, fetch the source code for the dependencies, and creates and maintains the right environment for you to build your project with the minimum of hassles.

Coming from a JavaEE background, where Maven reigns as a dependency management tool, I longed for the day when I could just specify the library I needed (and optionally, the exact version) and have it installed/included for each project automatically.

That day finally arrived for me when I discovered CocoaPods :]

In this tutorial, you’ll get hands on experience using CocoaPods. Specifically, you’ll use it to create an app that connects to popular television information site trakt.tv and fetches information about the shows that you (or somebody else) subscribed to, allowing you to show information about upcoming television episodes.

As you’ll see in this tutorial, using CocoaPods will make this project a lot easier. Read on to see for yourself! :]

Getting Started

Note: Before you proceed any further, note that this tutorial requires some familiarity with Xcode, creating screens via Interface Builder, working from the command line, using libraries/frameworks, and the JSON format. If you’re not familiar with any of these things, you might want to refer to some of the other tutorials on this site to brush up on the relevant subject.

CocoaPods is “the best way to manage library dependencies in Objective-C projects,” according to its website. And in this case, at least at the present time, the advertising is true. :]

Instead of downloading some code from GitHub and copying it to your project (and thus making future updates a pain), you can let CocoaPods do it all for you!

The app you’re going to build in this tutorial will be pretty simple – we want to build an an app that displays information about upcoming TV shows based on information available at trakt.tv. In case you weren’t aware of the site, trakt.tv helps you keep track of your favourite TV shows and to know when the next episode is on. The site does a lot more besides that but that isn’t relevant to our tutorial.

You’ll fetch a JSON feed from trakt.tv using the AFNetworking network library, parse it to extract the data, and show the results in a scroll view. You’ll also use several other third-party libraries along the way to make your life easier. :]

To get started, first install CocoaPods. CocoaPods runs on Ruby, and that’s the only dependency you’ll need. Happily, all versions of Mac OS X ship with Ruby. So the only preparation you need to do (if you’re not using OS X Lion) is to update RubyGems.

To do so, type the following command in Terminal:

sudo gem update --system

If you’re using a fresh install of Mac OS X Lion and a new installation of Xcode from the Mac App Store, in addition to the above, you might need to install the Command Line Tools for Xcode. You can download and install it from here, or by opening Xcode, navigating the menu to Xcode > Preferences > Downloads > Components, finding Command Line Tools, and clicking on either Update or Install, if the button is enabled. If it says “installed”, then you’re set.

Installing command line tools

With that done, installing CocoaPods is as simple as typing (also in Terminal):

sudo gem install cocoapods
pod setup

Installing CocoaPods screenshot

Creating a “Hello World” Project

Start up Xcode and create a new project with the iOS\Application\Single View Application template.

Enter CocoaPodsExample for the product name, enter the company identifier you used when creating your App ID, set device family to iPhone, and make sure Use Storyboards and Use Automatic Reference Counting are checked (but leave Include Unit Tests unchecked):

Create project setting screenshot

Click Next and choose a location to save your project.

Then download placeholder.png and drag & drop it into the project root, making sure that the “Copy items into destination group’s folder (if needed)” checkbox is ticked if you are dragging and dropping from a temporary folder.

Adding image to the project

Now, open MainStoryboard.storyboard and follow these steps:

  1. Add a scroll view. To do this, select it in the Object Library and drag it into your current view. Make sure it fills the view.
  2. Edit the scroll view attributes (in the Attributes Inspector), deselecting Shows Horizontal Scrollers and Shows Vertical Scrollers, and selecting Scrolling Enabled, Paging Enabled and Direction Lock Enabled. Also, change the background color to Dark Gray.
  3. Add a page control to your view, making sure it remains a sibling (not a child) of the scrollview. The page control needs to be in front of the scrollview (otherwise it won’t be visible).

The storyboard should look something like this:

Storyboard image

Now, wire up the scroll view to the view controller by attaching it to a new outlet named showsScrollView and setting the view controller as the scroll view’s delegate.

Also, wire up the page control, and name its outlet showPageControl. Link Value Changed event to a new method, called pageChanged.

Now, close Xcode. Yeah, you read that right! It’s time to create your pod file.

Installing Your First Dependency

Open Terminal, and navigate to the folder where your project is. Type the following:

touch Podfile
open -e Podfile

TextEdit should open up showing an empty file. You just created the pod file and opened it! Ready to add some content to the empty pod file?

Copy and paste the following lines into the TextEdit window:

platform :ios

pod 'AFNetworking', '0.9.1'

As you can see, the Podfile format is very simple. First, you set the platform to iOS (since some libraries are only available for either iOS or Mac OS X but not both).

Then, you added your first dependency, AFNetworking, and specified that you wanted version 0.9.1 (the latest as of the writing of this tutorial).

This link has more detailed information about the Podfile format. You might want to read it if you want to do more complicated stuff like specifying library versions conditionally – for instance, specifying anything higher than a specific version or a specific version range.

Now, save the file and close TextEdit, going back to terminal. Ready to configure your project?

Issue the following command via Terminal:

pod install

You should see output similar to the following:

Updating spec repo `master'
Installing AFNetworking (0.9.1)
Generating support files

It might also tell you something like this:

[!] From now on use `CocoaPodsExample.xcworkspace'

If you type ls now (or browse the project folder using Finder), you’ll see that CocoaPods created a Pods folder – where it stores all dependencies – and CocoaPodsExample.xcworkspace.

VERY IMPORTANT!

From now on, as the command-line warning mentioned, you must always open the workspace (CocoaPodsExample.xcworkspace) and not the project!

Close the Xcode project (if you had it open) and open CocoaPodsExample.xcworkspace to continue and test if it worked.

Testing AFNetworking

To test if AFNetworking was successfully added and if CocoaPods really works, create a new file with the iOS\Cocoa Touch\Objective-C class template. Name the class TraktAPIClient, and make it a subclass of NSObject. Remember to add the new file to the CocoaPodsExample project and not the Pods project – if you look at your Project Navigator, you should see that you now have two separate projects in your workspace.

Open TraktAPIClient.h and replace the existing code with the following:

#import <Foundation/Foundation.h>
#import <AFHTTPClient.h>
 
extern NSString * const kTraktAPIKey;
extern NSString * const kTraktBaseURLString;
 
@interface TraktAPIClient : AFHTTPClient
 
+(TraktAPIClient *)sharedClient;
 
@end

This is what the code above does:

  1. The first line is the standard import of the Foundation header file.
  2. The second line imports the header for a class from AFNetworking. This class, AFHTTPClient, will be the superclass of TraktAPIClient.
  3. The next two lines declare two string constants with the modifier extern, which says that their value will be in another file (in this case, TraktAPIClient.m).
  4. We then specify that TraktAPIClient will be a subclass of AFHTTPClient.
  5. Finally, the instance method will allow us to get a singleton instance from TraktAPIClient.

Why did we create the TraktAPIClient instance when it looks as if the AFHTTPClient class already handles HTTP requests? This is because we’d like to create a specialized handler class which allows us to access the trakt.tv API and make a lot of requests to the same base URL (and using the same API key – we’ll get to the API key in a bit). This helps us encapsulate the functionality for accessing trakt.tv in a single class.

Now, open TraktAPIClient.m and add replace its content with the following:

#import "TraktAPIClient.h"
#import <AFJSONRequestOperation.h>
 
NSString * const kTraktAPIKey = @"fc3df235908f83107cedd7914950d7a0";
NSString * const kTraktBaseURLString = @"http://api.trakt.tv";
 
@implementation TraktAPIClient
 
+(TraktAPIClient *)sharedClient {
    static TraktAPIClient *_sharedClient = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        _sharedClient = [[self alloc] initWithBaseURL:[NSURL URLWithString:kTraktBaseURLString]];
    });
    return _sharedClient;
}
 
-(id)initWithBaseURL:(NSURL *)url {
    self = [super initWithBaseURL:url];
    if (!self) {
        return nil;
    }
    [self registerHTTPOperationClass:[AFJSONRequestOperation class]];
    // Accept HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
	[self setDefaultHeader:@"Accept" value:@"application/json"];
    self.parameterEncoding = AFJSONParameterEncoding;
    return self;
}
 
@end

First, we import AFJSONRequestOperation.h, as responses to all requests will be in JSON format. Then, we set the values of the constants declared via the header. These values specify the API Key to be used in making any requests to trakt.tv and the base URL for all requests.

VERY IMPORTANT!

The API key in this example was created only for this tutorial. If you make an app, please create an account at trakt.tv and get your own API key!

Next, we implement sharedClient, which, following the singleton design pattern, returns a single instance of the class (instead of creating new instances) any time it is called. The core of this method relies on the Grand Central Dispatch (GCD) function called dispatch_once, which executes a block object once and only once for the lifetime of an application. This ensures that the creation of the TraktAPIClient instance via the call to sharedClient will result in only one instance of the object.

Finally, we override initWithBaseURL:, which is defined in AFHTTPClient.m. This way, we can create a customized initialiser which expects JSON responses in reply to all requests. We also specify that all parameters will be sent as JSON since that’s the way the trait API works.

Now open AppDelegate.m and add the following right after the existing import line:

#import <AFNetworking.h>

Next add the following to application:didFinishLaunchingWithOptions: (before the return statement):

[AFNetworkActivityIndicatorManager sharedManager].enabled = YES;

The above enables the automatic network activity indication manager that AFNetworking supports. This way, you don’t have to enable the network activity indicator each time you make a query and then turn it off each time the query completes.

Now, open ViewController.m and add the following imports right after the last one:

#import "TraktAPIClient.h"
#import <AFNetworking.h>

Then, replace viewDidLoad with the following:

-(void)viewDidLoad {
    [super viewDidLoad];
    // 1 - Create trakt API client
    TraktAPIClient* client = [TraktAPIClient sharedClient];
    // 2 - Create date instance with today's date
    NSDate* today = [NSDate date];
    // 3 - Create date formatter
    NSDateFormatter* formatter = [[NSDateFormatter alloc] init];
    formatter.dateFormat = @"yyyyMMdd";
    NSString* todayString = [formatter stringFromDate:today];
    // 4 - Create API query request
    NSString* path = [NSString stringWithFormat:@"user/calendar/shows.json/%@/%@/%@/%d", kTraktAPIKey, @"marcelofabri", todayString, 3];
    NSURLRequest* request = [client requestWithMethod:@"GET" path:path parameters:nil];
    // 5 - Create JSON request operation
    AFJSONRequestOperation* operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
        // 6 - Request succeeded block
        NSLog(@"%@", JSON);
    } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
        // 7 - Request failed block
    }];
    // 8 - Start request
    [operation start];
}

This code uses a date formatter to put today’s date into the format expected by the API. It also constructs the URL path, using the API key, the user name (in this case my own), the initial date, and how many days of data to fetch.

Then, it creates an AFJSONRequestOperation, passing the request and two blocks (one that executes on success and the other executed on failure) as parameters. The success block prints out the already-parsed JSON.

Compile and run. You should see a dictionary in console output, like this:

Console output, displaying the JSON

Building the Sample Project

Now that you’ve seen CocoaPods in action, it’s time to add more libraries.

Open Podfile (you will have to open it via the command-line as before or use Finder) and append the following lines:

pod 'SSToolkit'
pod 'ConciseKit'

Save the file, and install the dependencies (by using “pod install” via the Terminal, as before).

SSToolkit is a handy collection of solutions to common issues faced by iOS iOS developers. In our case, you’ll use it to check if the device has a Retina display.

ConciseKit makes programming in Objective-C less verbose, creating aliases for most-used methods.

Open ViewController.m and add the following imports, just after the last one:

#import <ConciseKit.h>
#import <SSCategories.h>

Now, add these variables into ViewControllers’s private interface (the section which begins with @interface ViewController (), right after the imports) by replacing the whole section with the following (or you can add the curly braces in as needed and add the variables within):

@interface ViewController () {
    NSArray *jsonResponse;
    BOOL pageControlUsed;
    int previousPage;
    NSMutableSet *loadedPages;
}
@end

Create a method called loadShow:, at the bottom of the file:

-(void)loadShow:(int)index {
    // empty for now...
}

This method will be responsible for presenting a page to the user that displays information about a selected TV show episode.

Now we need to alter viewDidLoad a bit so that it does something useful with the JSON instead of simply logging it. Add the following before section #5:

// 4.1 - Initialize variables
loadedPages = [NSMutableSet set];
previousPage = -1;

Remove the logging in section #6 and add the following lines in its place:

// 6.1 - Load JSON into internal variable
jsonResponse = JSON;
// 6.2 - Get the number of shows
int shows = 0;
for (NSDictionary* day in jsonResponse) {
    shows += [[day $for: @"episodes"] count];
	// $for: above is the same as objectForKey: - we're using ConciseKit here.
}
// 6.3 - Set up page control
showPageControl.numberOfPages = shows;
showPageControl.currentPage = 0;
// 6.4 - Set up scroll view
showsScrollView.contentSize = CGSizeMake(self.view.bounds.size.width * shows, showsScrollView.frame.size.height);
// 6.5 - Load first show
[self loadShow:0];

You modified the success block so that, instead of logging the JSON, the page control is configured along with the scroll view. Also, you call the loadShow: method to load the first show in the list of shows returned.

Now you can present some info about a show by implementing loadShow:.

-(void)loadShow:(int)index {
    // 1 - Does the pages array contain the specified page?
    if (![loadedPages containsObject:$int(index)]) {
        // $int(x) is the same as [NSNumber numberWithInt:x]
        // 2 - Find the show for the given index
        int shows = 0;
        NSDictionary *show = nil;
        for (NSDictionary *day in jsonResponse) {
            int count = [[day $for: @"episodes"] count];
            // 3 - Did we find the right show?
            if (index < shows + count) {
                show = [[day $for:@"episodes"] $at: index-shows];
                break;
            }
            // 4 - Increment the shows counter
            shows += count;
        }
        // 5 - Load the show information
        NSDictionary *episodeDict = [show $for:@"episode"];
        NSDictionary *showDict = [show $for:@"show"];
        // 6 - Display the show information
        UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(index * showsScrollView.bounds.size.width, 40, showsScrollView.bounds.size.width, 40)];
        label.text = [showDict $for: @"title"];
        label.backgroundColor = [UIColor clearColor];
        label.font = [UIFont systemFontOfSize:18];
        label.textAlignment = UITextAlignmentCenter;
        [showsScrollView addSubview:label];
        // 7 - Add the new page to the loadedPages array
        [loadedPages addObject:$int(index)];
    }
}

Compile and run. You should see something like this:

iPhone screenshot, displaying the show title

Cool! Tonight a new episode of The Simpsons will air! But which episode?

Add the following to loadShow: just before section #7:

// 6.1 - Create formatted airing date        
static NSDateFormatter *formatter = nil;
if (!formatter) {
    formatter = $new(NSDateFormatter);
    formatter.dateStyle = NSDateFormatterLongStyle;
    formatter.timeStyle = NSDateFormatterShortStyle;
    formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"PST"];
}
NSTimeInterval showAired = [[episodeDict $for: @"first_aired_localized"] doubleValue];
NSString *showDate = [formatter stringFromDate:[NSDate dateWithTimeIntervalSince1970: showAired]];
// 6.2 - Create label to display episode info
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(index * showsScrollView.bounds.size.width, 360, showsScrollView.bounds.size.width, 40)];
NSString* episode  = [NSString stringWithFormat:@"%02dx%02d - \"%@\"",
    [[episodeDict valueForKey:@"season"] intValue], 
    [[episodeDict valueForKey:@"number"] intValue],
    [episodeDict objectForKey:@"title"]];
lbl.text = [NSString stringWithFormat:@"%@\n%@", episode, showDate];
lbl.numberOfLines = 0;
lbl.textAlignment = UITextAlignmentCenter;
lbl.textColor = [UIColor whiteColor];
lbl.backgroundColor = [UIColor clearColor];
[showsScrollView addSubview:lbl];

The above code creates a date formatter so the date is human-readable, and creates a label with some info about the episode, such as season, episode number, title and also the date and time it’s going to be aired.

Compile and run! Now you can see that The Simpsons is already in its 23rd season!

iPhone screenshot, showing episode info

Doesn’t it feel as if there’s a giant void at the center of the screen that’s calling out to be filled? What if you put an image there?

Add the following code just before section #7 in loadShow::

// 6.3 - Get image
NSString *posterUrl = [[showDict $for: @"images"] $for: @"poster"];
if ([[UIScreen mainScreen] isRetinaDisplay]) {
    posterUrl = [posterUrl stringByReplacingOccurrencesOfString:@".jpg" withString:@"-300.jpg"];
} else {
    posterUrl = [posterUrl stringByReplacingOccurrencesOfString:@".jpg" withString:@"-138.jpg"];            
}
// 6.4 - Display image using image view
UIImageView *posterImage = $new(UIImageView); 
// $new(class) is the same as [[class alloc] init] - courtesy of ConciseKit        
posterImage.frame = CGRectMake(index * showsScrollView.bounds.size.width + 90, 80, 150, 225);
[showsScrollView addSubview:posterImage];
// 6.5 - Asynchronously load the image        
[posterImage setImageWithURL:[NSURL URLWithString:posterUrl] placeholderImage:[UIImage imageNamed:@"placeholder.png"]];

This code first decides what version of image to download since there is no need to download a larger image on a non-retina device. (Note that the isRetinaDisplay is a helper method that we get via the SSToolkit.) After that, a UIImageView is created and added to the scroll view.

Finally, the image is downloaded and displayed via the image view, using a convenience method provided by AFNetworking. This method also sets a placeholder image that is displayed until the download is finished.

Compile and run! You should see a beautiful poster of the show.

iPhone screenshot, showing the poster

Wow! You now have enough information displayed about the first show in the list but what about the rest? We need to show information about the other shows as the view is paged, right?

Replace pageChanged: with the following:

-(IBAction)pageChanged:(id)sender {
    // Set flag
    pageControlUsed = YES;
    // Get previous page number
    int page = showPageControl.currentPage;
    previousPage = page;
    // Call loadShow for the new page
    [self loadShow:page];
    // Scroll scroll view to new page
    CGRect frame = showsScrollView.frame;
    frame.origin.x = frame.size.width * page;
    frame.origin.y = 0;
    [UIView animateWithDuration:.5 animations:^{
        [showsScrollView scrollRectToVisible:frame animated:NO];
    } completion:^(BOOL finished) {
        pageControlUsed = NO;
    }];
}

First, the control variable pageControlUsed is set to YES, indicating that the new page will be shown because the user selected it with the page control, and not by scrolling the scrollview. (We’ll need this later when we handle scrolling using the scrollview.)

Then, the new page is loaded, and its frame calculated, so it can be displayed.

Compile and run! Now navigate through pages using the page control. Cool, isn’t it?

But, something’s missing… What about changing pages by scrolling? If you try to do that, you’ll notice that you get blank pages, unless you’d already scrolled to that page using the page control. Let’s fix that.

Paste the following scrollview delegate methods at the end of the file:

-(void)scrollViewDidScroll:(UIScrollView *)sender {
    // Was the scrolling initiated via page control?
    if (pageControlUsed) {
        return;
    }
    // Figure out page to scroll to
    CGFloat pageWidth = sender.frame.size.width;
    int page = floor((sender.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
    // Do not do anything if we're trying to go beyond the available page range
    if (page == previousPage || page < 0 || page >= showPageControl.numberOfPages) 
        return;
    previousPage = page;
    // Set the page control page display
    showPageControl.currentPage = page;
    // Load the page
    [self loadShow:page];
}
 
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    pageControlUsed = NO;
}

Note the use of pageControlUsed. That’s because when the scroll view offset is changed in pageChanged (when you change the page using the page control), the scrollViewDidScroll: method is called, but if we handled the scrolling at that point, we’d be loading the same page twice. So we need to detect when scrolling is initiated via the page control and do nothing.

Compile and run! You can navigate through the shows by scrolling now! Fantastic, isn’t it?

But what if the user wants to know more about the show? trakt has a page for every show registered, and its URL is in the information we received. You can use NIAttributedLabel to present it.

Nimbus Attributed Label is a submodule of Nimbus – a framework created to replace three20 (and fix some of the issues present in it).

Open the Podfile and add this dependency:

pod 'Nimbus/AttributedLabel'

Save the file, and do a pod install as before. Do you notice anything different in this dependency? What is that slash in the middle of its name?!

The slash means that AttributedLabel is a submodule of Nimbus, so it needs Nimbus installed to work. The slash is a very helpful indicator with libraries that offer a core and a lot of extensions (like Nimbus).

Open ViewController.h and add the following import right after the import of UIKit.

#import <NIAttributedLabel.h>

Also, change the ViewController interface declaration so it conforms to NIAttributedLabelDelegate protocol – it should look like this:

@interface ViewController : UIViewController<UIScrollViewDelegate, NIAttributedLabelDelegate>

Now, switch to ViewController.m and implement one of the NIAttributedLabelDelegate methods, at the bottom of the file:

- CocoaPodsExample(void)attributedLabel:(NIAttributedLabel *)attributedLabel didSelectTextCheckingResult:(NSTextCheckingResult *)result atPoint:(CGPoint)point {
    [[UIApplication sharedApplication] openURL:result.URL];
}

NIAttributedLabelDelegate supports links, and the method implemented is called when a link is selected. The method calls UIApplication to open the link in Safari, which is the default browser.

But how can one add a link to the label displayed in the app? Simple. Change the implementation of loadShow: in section #6, so that the label that displays the show title is an NIAttributedLabel, and not a UILabel.

Replace section #6 with the following:

// 6 - Display the show information
NIAttributedLabel* label = [[NIAttributedLabel alloc] initWithFrame:CGRectMake(index * showsScrollView.bounds.size.width, 40, showsScrollView.bounds.size.width, 40)];
label.text = [showDict $for: @"title"];
label.backgroundColor = [UIColor clearColor];
label.linkColor = [UIColor redColor];
label.font = [UIFont systemFontOfSize:18];
label.textAlignment = UITextAlignmentCenter;
[label addLink: [NSURL URLWithString:[showDict $for: @"url"]] range:NSMakeRange(0, label.text.length)];
label.delegate = self;
[showsScrollView addSubview:label];

The main difference here is the existence of a linkColor property, and the addLink: method, which is called to set an NSURL for a range of the label’s text (in this case, the whole string). It’s also important to set the label’s delegate to self, which represents the current instance of the ViewController.

Build and run! You should see the show title in red, and if you click it, Safari will open, with the show page from trakt.

Where To Go From Here?

You can download an example project with all of the code from this tutorial here.

Now that you know the CocoaPods basics, you can navigate through their wiki to discover more possibilities, including creating your own Podspec and eventually submitting it to the official repository. More about this is explained here.

You can also use a dependency without creating a Podspec. This link has more info about that (and other options that a Podfile supports).

To check if CocoaPods already supports a specific library, you can search the CocoaPods website.

Here are some of the libraries I think are most useful:

  • AFNetworking: Network connectivity and response handling.
  • ASIHTTPRequest: Network connectivity and response handling. Not updated any longer but still works.
  • BlocksKit: Framework to make using blocks easier.
  • ConciseKit: Helps keep your code short and concise by adding shortcuts for often used methods.
  • CorePlot: Graphing and plotting framework.
  • EGOTableViewPullRefresh: Provides pull-to-refresh functionality.
  • Facebook-iOS-SDK: Allows easy Facebook integration.
  • JSONKit: Provides great JSON parsing functionality.
  • MBProgressHUD: An activity indicator that can be added to your views.
  • Nimbus: A comprehensive toolkit of modules aimed at replacing Three20.
  • QuickDialog: Quick and easy dialog screens for iOS.
  • Reachability: Network access detection.
  • SFHFKeychainUtils: Keychain utilities.
  • ShareKit: Easy sharing of content via multiple methods and social networks.

Of course there are many more, but I don’t want to spoil the pleasure of discovery! It’s a nice exercise to open the specs repository and check what’s available. You never know what new and useful libraries you might find!

Also, check out the trakt API. It’s well-documented and you can do a lot of things with it! (I made a python script to check how much time I “invest” on TV shows, just for fun!)

Regarding the sample application, there are many improvements you could make, such as:

  • What happens if there isn’t a TV show for the given date range?
  • What if there are a lot of shows? None of the pages that are loaded are thrown away, and this can quickly consume a lot of memory!
  • There’s more information to be displayed – like a synopsis, the channel airing the show, etc.

I hope you enjoyed the tutorial, and I’ll be glad to read your feedback in the forums. Also, if you create a Podspec, share with everyone! Know of another useful library? Tell us!


This is a post by iOS Tutorial Team Member Marcelo Fabri, an iOS developer working at Movile. Check out his personal website or find him on Twitter or on .

Marcelo Fabri
Marcelo Fabri

Marcelo is a CS student at Unicamp and an iOS Developer at Movile.

At his little spare time, he works on his side projects and watches (a lot) of tv shows. He is also available to contract work.

You can reach him via LinkedIn, email or his personal site.

User Comments

49 Comments

[ 1 , 2 , 3 , 4 ]
  • Thanks for the tutorial, but I found it sort of lacking in actual Pod detail, it could have used a lot more explanation on the Pods part. IE, the syntax of the pod file, how to get different versions of pod libraries, setting min OS versions, etc.
    FirebirdStravESP01
  • Thanks for your tutorial so much. It's really helpful to me but i got an issues with pod command :
    [!] Invalid `Podfile` file: undefined local variable or method `OpenCV' for #. Updating CocoaPods might fix the issue.
    Could your help me to resolve this issues
    Thank,
    oishi89
  • When I am shooting the command
    pod install
    I am getting

    Analyzing dependencies
    /Library/Ruby/Gems/1.8/gems/cocoapods-0.28.0/lib/cocoapods/executable.rb:55: warning: Insecure world writable dir /usr in PATH, mode 040777
    [!] The `master` repo requires CocoaPods 0.29.0 -
    Update CocoaPods, or checkout the appropriate tag in the repo.
    RupanjanSen
  • This is a very nice tutorial except the example code is no longer compatible with AFNetworking and iOS 7.
    AFNetworking no longer has an AFHTTPClient class, but has split the functionality between other
    classes. It would be very nice if someone could update this.
    papley
[ 1 , 2 , 3 , 4 ]

Other Items of Interest

Ray's Monthly Newsletter

Sign up to receive a monthly newsletter with my favorite dev links, and receive a free epic-length tutorial as a bonus!

Advertise with Us!

Hang Out With Us!

Every month, we have a free live Tech Talk - come hang out with us!


Coming up in May: Procedural Level Generation in Games with Kim Pedersen.

Sign Up - May

Coming up in June: WWDC Keynote - Podcasters React! with the podcasting team.

Sign Up - June

Vote For Our Next Book!

Help us choose the topic for our next book we write! (Choose up to three topics.)

    Loading ... Loading ...

Our Books

Our Team

Tutorial Team

  • Jake Gundersen

... 55 total!

Editorial Team

  • Alexis Gallagher

... 21 total!

Code Team

  • Orta Therox

... 1 total!

Translation Team

  • Rodrigo Salles

... 38 total!

Subject Matter Experts

... 4 total!