Introduction to CocoaPods Tutorial

Joshua Greene
Make an app with several library dependencies with ease!

Make an app with several library dependencies with ease!

4/14/2014: Fully updated for CocoaPods 0.31 and iOS 7 (original post by Marcelo Fabri, update by Joshua Greene).

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. Just imagine how difficult it would be if you had to implement everything from scratch!

Without a dependency management tool, you might simply add each library’s code to your project. However, this has several disadvantages:

  • Library code is stored within your project, wasting space.
  • There’s no central place where you can see all libraries that are available.
  • It can be difficult to find and update a library to a new version, especially if several libraries need to be updated together.
  • Downloading and including libraries within your project may tempt you to make changes to the downloaded code and just leave it there (making it harder to update them later).

A dependency management tool can help you overcome these issues. It will fetch library source code, resolve dependencies between libraries, and even create and maintain the right environment to build your project with the minimum of hassles.

You’ll get hands on experience using CocoaPods for dependency management in this tutorial. Specifically, you will create an app that uses several open-source libraries to fetch and display information from a popular television and movie information site, trakt.tv.

CocoaPods will make this project much easier. Read on to see for yourself!

Getting Started

Before you begin: This tutorial assumes you are familiar with Xcode, working with the command line, using AFNetworking, and the JSON format. If you’re completely new to any of these (a basic understanding should be okay), you should refer to the other tutorials on this site first.

According to its website, CocoaPods is “the best way to manage library dependencies in Objective-C projects.” And in this case, the advertising is true!


True Dat!

Instead of downloading code from GitHub and copying it into your project (and thus making future updates difficult), you can let CocoaPods do it for you.

In this tutorial, you will be building an app that displays upcoming TV episodes using trakt.tv. If you haven’t heard of it, trakt helps you keep track of the shows that you watch. Trakt has several other features, but this is the only one that you will be using in this tutorial.

You will retrieve show information from a JSON feed provided by trakt. To simplify downloading, parsing, and showing results, you will use AFNetworking and a few other open-source libraries along the way.

To get started, you first need to install CocoaPods. CocoaPods runs on Ruby, yet that’s the only dependency it has. Fortunately, all recent versions of Mac OS X (since OS X 10.7 Lion) ship with Ruby already installed. So all you need to do is update RubyGems (just to make sure you have a recent version).

To do so, open Terminal and type the following command:

sudo gem update --system

Enter your password when requested. The Terminal output should look something like this:

Terminal Output

This update may take a little while, so be patient and give it a few minutes to complete. You can also expect some documentation in the Terminal window about the latest version; you can ignore this for now.

Next, you need to install CocoaPods. Type this command in Terminal to do so:

sudo gem install cocoapods

You may get this prompt during the install process:

rake's executable "rake" conflicts with /usr/bin/rake
Overwrite the executable? [yN]

If so, just enter y to continue. (This warning is raised because the rake gem is updated as part of the install process. You can safely ignore it.)

Lastly, enter this command in Terminal to complete the setup of CocoaPods:

pod setup

This process will likely take a while as this command clones the CocoaPods Specs repository into ~/.cocoapods/ on your computer.

Great, you’re now setup to use CocoaPods!


Oh yeah!

Introducing the “Show Tracker” App

Download the starter project for this tutorial here. This provides a basic UI to get you started – no dependencies have been added yet.

Open Main.storyboard, and you will see just one view controller:


View Controller

This is the initial view controller, simply called ViewController.

It has a UIScrollView connected via an IBOutlet to its showsScrollView property and a UIPageControl connected to showsPageControl.

It is also set as the delegate for showsScrollView and currently has a single method, pageChanged:, which is connected to the value changed event of showsPageControl.

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 directory containing your ShowTracker project by using the cd command:

cd ~/Path/To/Folder/Containing/ShowTracker

Next enter this command:

pod init

This will create a default Podfile for your project. The Podfile is where you define the dependencies your project relies on.

Type this command to open Podfile using Xcode for editing:

open -a Xcode Podfile

Note: You shouldn’t use TextEdit to edit the pod file because TextEdit likes to replace standard quotes with more graphically appealing quotes. This can cause CocoaPods to get confused and display errors, so it’s best to just use Xcode or another programming text editor.

The default Podfile should look like this:

# Uncomment this line to define a global platform for your project
# platform :ios, "6.0"
 
target "ShowTracker" do
 
end

Replace # platform :ios, "6.0" with the following:

platform :ios, "7.0"

This tells CocoaPods that your project is targeting iOS 7.

Many libraries – AFNetworking included – have a minimum iOS version requirement. If you omit this line, CocoaPods assumes a default target version (currently iOS 4.3).

If you’ve only ever programmed in Objective-C, this may look a bit strange to you – that’s because the pod file is actually written in Ruby. You don’t need to know Ruby to use CocoaPods, but you should be aware that even minor text errors will typically cause CocoaPods to throw an error.

It’s finally time to add your first dependency using CocoaPods! Copy and paste the following into your pod file, right after target "ShowTracker" do:

pod 'AFNetworking', '2.2.1'

This tells CocoaPods that you want to include AFNetworking version 2.2.1 (the latest as of the writing of this tutorial) as a dependency for your project.

This link has more information about the Podfile format and syntax. If you want to do more complicated stuff (like specifying “any version higher than” a specific version of a library), you should definitely check it out.

Save and close the pod file.

You now need to tell CocoaPods to “install” the dependencies for your project. Enter the following command in Terminal to do so (making sure that you’re still in the directory containing the ShowTracker project and Podfile):

pod install

You should see output similar to the following:

Analyzing dependencies
Downloading dependencies
Installing AFNetworking (2.2.1)
Generating Pods project
Integrating client project

It might also tell you something like this:

[!] From now on use `ShowTracker.xcworkspace`.

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

VERY IMPORTANT!

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

Close the Xcode project (if you had it open) and open ShowTracker.xcworkspace.

Register for Trakt

Before you can use the Trakt APIs, you first need to register for a free account. Don’t worry – it’s fast and easy to do!

After registering, go to the Settings -> API page to get your API key. Go ahead and leave this page open as you’ll need it soon.

Testing AFNetworking

To verify that AFNetworking was successfully added, create a new file with the iOS -> Cocoa Touch -> Objective-C class template.

Name the class TraktAPIClient, and make it a subclass of NSObject.

Make sure you add the new file to the ShowTracker project and not the Pods project – if you look at your Project Navigator, you’ll see that you now have two separate projects in your workspace.


Adding TraktAPIClient

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

// 1
#import <AFNetworking/AFNetworking.h>
 
// 2
extern NSString * const kTraktAPIKey;
extern NSString * const kTraktBaseURLString;
 
// 3
@interface TraktAPIClient : AFHTTPSessionManager
 
// 4
+ (TraktAPIClient *)sharedClient;
 
// 5
- (void)getShowsForDate:(NSDate *)date
               username:(NSString *)username
           numberOfDays:(int)numberOfDays
                success:(void(^)(NSURLSessionDataTask *task, id responseObject))success
                failure:(void(^)(NSURLSessionDataTask *task, NSError *error))failure;
 
@end

Here’s what you’re doing:

  1. First import the main header for AFNetworking, which is AFNetworking.h. This includes AFHTTPSessionManager, which will be the super class of TraktAPIClient, and other related networking classes.
  2. Next, declare two string constants with the extern modifier. This means these strings will be globally available.
  3. Change TraktAPIClient to extend AFHTTPSessionManager instead of NSObject, as mentioned in step 1.
  4. Declare sharedClient, which will return a singleton instance for TraktAPIClient.
  5. Lastly, declare a helper method that will make it easier to use the trakt API to get shows for a specific date, username, and number of days.

You might be wondering, “why did I create TraktAPIClient when AFHTTPSessionManager already handles HTTP requests?”

TraktAPIClient will make it easier to access the trakt API and make a lot of requests to the same base URL, using the same API key. This also encapsulates all the networking calls and responsibility into a single class.

Open TraktAPIClient.m and replace its contents with the following:

#import "TraktAPIClient.h"
 
// Set this to your Trakt API Key
NSString * const kTraktAPIKey = @"PASTE YOUR API KEY HERE";
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;
}
 
- (instancetype)initWithBaseURL:(NSURL *)url {
 
    self = [super initWithBaseURL:url];
    if (!self) {
        return nil;
    }
 
    self.responseSerializer = [AFJSONResponseSerializer serializer];
    self.requestSerializer = [AFJSONRequestSerializer serializer];
    return self;
}
 
- (void)getShowsForDate:(NSDate *)date
               username:(NSString *)username
           numberOfDays:(int)numberOfDays
                success:(void(^)(NSURLSessionDataTask *task, id responseObject))success
                failure:(void(^)(NSURLSessionDataTask *task, NSError *error))failure
{
    NSDateFormatter* formatter = [[NSDateFormatter alloc] init];
    formatter.dateFormat = @"yyyyMMdd";
    NSString* dateString = [formatter stringFromDate:date];
 
    NSString* path = [NSString stringWithFormat:@"user/calendar/shows.json/%@/%@/%@/%d",
                      kTraktAPIKey, username, dateString, numberOfDays];
 
    [self GET:path parameters:nil success:^(NSURLSessionDataTask *task, id responseObject) {
        if (success) {
            success(task, responseObject);
        }
    } failure:^(NSURLSessionDataTask *task, NSError *error) {
        if (failure) {
            failure(task, error);
        }
    }];
}
 
@end

This code fulfills all the promises you made in the header file:

First, you declare the string constants. Make sure you replace PASTE YOUR KEY HERE with your actual trakt API key.

Next, you implement sharedClient, which uses Grand Central Dispatch (GCD) to create a singleton instance.

You then override initWithBaseURL: and set responseSerializer and requestSerializer to the default JSON serializer for each.

Lastly, you create the helper method to get shows using the format expected by trakt.

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

#import <AFNetworking/AFNetworkActivityIndicatorManager.h>

Then add the following to application:didFinishLaunchingWithOptions: right before the return statement:

[AFNetworkActivityIndicatorManager sharedManager].enabled = YES;

This will automatically show the network activity indicator whenever AFNetworking is performing network requests.

Next, open ViewController.m and add the following import right after the last one:

#import "TraktAPIClient.h"

Then, replace viewDidLoad with the following:

- (void)viewDidLoad
{
    [super viewDidLoad];
 
    TraktAPIClient *client = [TraktAPIClient sharedClient];
 
    [client getShowsForDate:[NSDate date]
                   username:@"rwtestuser"
               numberOfDays:3
                    success:^(NSURLSessionDataTask *task, id responseObject) {
                        NSLog(@"Success -- %@", responseObject);
                    }
                    failure:^(NSURLSessionDataTask *task, NSError *error) {
                        NSLog(@"Failure -- %@", error);
                    }];
}

This code calls the helper method you just setup to get the shows for today and the next 3 days.

Note: this API queries for tv episodes on a trakt user’s watch list. If you want to use your own username, you will first need to add shows to your watch list from the tv shows category. If you don’t want to do this, use rwtestuser as the username, which already has shows added to it.

Build and run, and you should see output in the console similar to the following:


Get Shows NSLog

Add More Pods

Now that you’ve seen CocoaPods in action, there’s only one thing to do…


Add More Pods!

Well, actually… you should strive to include as few pods as possible in each of your projects. While CocoaPods makes it easier to update library dependencies, you’re still going to have to update your own code from time to time when you update libraries.

Keeping your dependencies under control is the best way to go in the long run.

You need to add two more dependencies for this project. Rather than opening PodFile from the command line, you can now find it in the Pods target in the workspace.

Podfile In Workspace

Open Podfile and append the following right after the AFNetworking line:

pod 'SAMCategories', '0.5.2'
pod 'Nimbus/AttributedLabel', '1.2.0'

Save the file, and install the dependencies (via pod install in Terminal, as before).

Do you notice anything different about the Nimbus/AttributedLabel pod? What is that slash in the middle of its name?

Larger pods often break up their classes into several submodules that rely on a “core” module. In this case, the slash means that AttributedLabel is a submodule of Nimbus.

In case you’re not familiar with these libraries, here’s what they are:

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

Nimbus, short for NimbusKit, is another collection of useful categories and classes for iOS. You’ll use it mainly for its AttributedLabel component in this app.

Just to verify everything still works, go ahead and build the app. However, you should now see several warning messages!

“But wait a minute, I haven’t changed any of my project’s code!”, you might be thinking.

Whenever you add a dependency via CocoaPods, the pod’s source files are included within your project’s workspace. And whenever you compile your project, they’re compiled too.

So, if the pod you’re using has a lot of warnings (or worse, doesn’t compile at all), it may be an indicator that the library is no longer maintained.

In such a case, you can look for an alternative library on the CocoaPods website by using the search field. You can find detailed information about pods there too, including links to pods’ websites, documentation, and more.

In this case, however, the warnings are mainly due to recently deprecated methods in iOS 7 (mostly calls to sizeWithFont:), and you can safely ignore them.

Add the following to the top of Podfile to tell CocoaPods to silence all warnings from pod dependencies:

inhibit_all_warnings!

Run pod install again, build your project, and you shouldn’t see any warnings anymore.

Completing Show Tracker

Great, you now have all the dependencies you’ll need to complete Show Tracker, so let’s do it!

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

#import <AFNetworking/UIKit+AFNetworking.h>
#import <Nimbus/NIAttributedLabel.h>
#import <SAMCategories/UIScreen+SAMAdditions.h>

Next, add the following properties right after @interface ViewController ():

@property (nonatomic, strong) NSArray *jsonResponse;
@property (nonatomic) BOOL pageControlUsed;
@property (nonatomic) NSInteger previousPage;

These will be used to store downloaded shows information.

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

- (void)loadShow:(NSInteger)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 you need to modify viewDidLoad so that it does something useful with the response object instead of simply logging it. First add the following right after [super viewDidLoad];:

self.previousPage = -1;

Then replace the contents of the success block with the following:

// Save response object
self.jsonResponse = responseObject;
 
// Get the number of shows
NSInteger shows = 0;
for (NSDictionary *day in self.jsonResponse)
    shows += [day[@"episodes"] count];
 
// Set up page control
self.showsPageControl.numberOfPages = shows;
self.showsPageControl.currentPage = 0;
 
// Set up scroll view
self.showsScrollView.contentSize = CGSizeMake(CGRectGetWidth(self.view.bounds) * shows, CGRectGetHeight(self.showsScrollView.frame));
 
// Load first show
[self loadShow:0];

Now the responseObject JSON is stored, the page control and scroll view are setup, and loadShow: is called to load the first show on success.

You can now present information about a show by replacing loadShow: with the following:

- (void)loadShow:(NSInteger)index
{
    // 1 - Find the show for the given index
    NSDictionary *show = nil;
    NSInteger shows = 0;
 
    for (NSDictionary *day in self.jsonResponse) {
        NSInteger count = [day[@"episodes"] count];
 
        // 2 - Did you find the right show?
        if (index < shows + count) {
            show = day[@"episodes"][index - shows];
            break;
        }
 
        // 3 - Increment the shows counter
        shows += count;
    }
 
    // 4 - Load the show information
    NSDictionary *showDict = show[@"show"];
 
    // 5 - Display the show title
    UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(index * CGRectGetWidth(self.showsScrollView.bounds) + 20, 40, CGRectGetWidth(self.showsScrollView.bounds) - 40, 40)];
    titleLabel.text = showDict[@"title"];
    titleLabel.backgroundColor = [UIColor clearColor];
    titleLabel.textColor = [UIColor whiteColor];
    titleLabel.font = [UIFont boldSystemFontOfSize:18];
    titleLabel.textAlignment = NSTextAlignmentCenter;
 
    // 6 - Add to scroll view
    [self.showsScrollView addSubview:titleLabel];
}

Build and run, and you will see something like this:


Title Only Screenshot

Cool, tonight a new episode of The Walking Dead will air! But which episode?

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

// 5.1 - Create formatted airing date
static NSDateFormatter *formatter = nil;
if (!formatter) {
    formatter = [[NSDateFormatter alloc] init];
    formatter.dateStyle = NSDateFormatterLongStyle;
    formatter.timeStyle = NSDateFormatterShortStyle;
    formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"PST"];
}
 
NSDictionary *episodeDict = show[@"episode"];
 
NSTimeInterval showAired = [episodeDict[@"first_aired_localized"] doubleValue];
NSString *showDate = [formatter stringFromDate:[NSDate dateWithTimeIntervalSince1970: showAired]];
 
// 5.2 - Create label to display episode info
UILabel *episodeLabel = [[UILabel alloc] initWithFrame:CGRectMake(index * CGRectGetWidth(self.showsScrollView.bounds),
                                                         360, CGRectGetWidth(self.showsScrollView.bounds), 40)];
NSString* episode  = [NSString stringWithFormat:@"%02dx%02d - \"%@\"",
                      [[episodeDict valueForKey:@"season"] intValue],
                      [[episodeDict valueForKey:@"number"] intValue],
                      [episodeDict objectForKey:@"title"]];
episodeLabel.text = [NSString stringWithFormat:@"%@\n%@", episode, showDate];
episodeLabel.numberOfLines = 0;
episodeLabel.textAlignment = NSTextAlignmentCenter;
episodeLabel.textColor = [UIColor whiteColor];
episodeLabel.backgroundColor = [UIColor clearColor];
 
CGSize size = [episodeLabel sizeThatFits:CGSizeMake(CGRectGetWidth(self.view.frame),
                                          CGRectGetHeight(self.view.frame) - CGRectGetMinY(episodeLabel.frame))];
CGRect frame = episodeLabel.frame;
frame.size.width = self.view.frame.size.width;
frame.size.height = size.height;
episodeLabel.frame = frame;
 
[self.showsScrollView addSubview:episodeLabel];

This creates a label containing info about the episode, including season, episode number, title and a human-readable date and time it’s going to be aired.

Build and run, and you can now see that The Walking Dead is already in its 4th season!


Title Details Screenshot

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?

Still in loadShow:, add the following code just before section #6:

// 5.3 - Get image
NSString *posterUrl = showDict[@"images"][@"poster"];
if ([[UIScreen mainScreen] sam_isRetina]) {
    posterUrl = [posterUrl stringByReplacingOccurrencesOfString:@".jpg" withString:@"-300.jpg"];
} else {
    posterUrl = [posterUrl stringByReplacingOccurrencesOfString:@".jpg" withString:@"-138.jpg"];
}
 
// 5.4 - Display image using image view
UIImageView *posterImage = [[UIImageView alloc] init];
posterImage.frame = CGRectMake(index * CGRectGetWidth(self.showsScrollView.bounds) + 90, 105, 150, 225);
[self.showsScrollView addSubview:posterImage];
 
// 5.5 - Asynchronously load the image
[posterImage setImageWithURL:[NSURL URLWithString:posterUrl] placeholderImage:[UIImage imageNamed:@"placeholder.png"]];

This code first determines the image to download based on whether the device has a retina display (since there is no need to download a larger image on a non-retina device). Note that isRetinaDisplay is a helper method included from SSToolkit.

After that, a UIImageView is created and added to the scroll view.

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

Build and run, and you will see a beautiful poster of the show.


Title, Details, and Poster Screenshot

Great! You now have information displayed about the first show but what about the rest?

You first need to show information about the other shows as the view is paged via the showsPageControl.

Replace pageChanged: with the following:

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

Here 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 scroll view. (You’ll need this later when you handle scrolling using the scroll view.)

Then, the new page is loaded and its frame calculated. Finally, the new page is displayed on the screen.

Build and run. You can now navigate through pages using the page control. Simply tap on the circles in the page control and the screen will navigate to the next or previous page. 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 UIScrollViewDelegate methods at the end of the file:

- (void)scrollViewDidScroll:(UIScrollView *)sender
{
    // Was the scrolling initiated via page control?
    if (self.pageControlUsed)
        return;
 
    // Figure out page to scroll to
    CGFloat pageWidth = sender.frame.size.width;
    NSInteger 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 == self.previousPage || page < 0 || page >= self.showsPageControl.numberOfPages)
        return;
    self.previousPage = page;
 
    // Set the page control page display
    self.showsPageControl.currentPage = page;
 
    // Load the page
    [self loadShow:page];
}
 
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    self.pageControlUsed = NO;
}

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

Build and run, and you can now navigate through the shows by scrolling too!

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 the app has already received.

You can use NIAttributedLabel to present it.

At the top of ViewController.m, replace @interface ViewController () with the following:

@interface ViewController () <NIAttributedLabelDelegate>

This declares that ViewController conforms to the NIAttributedLabelDelegate protocol.

Now add the following NIAttributedLabelDelegate method at the bottom of ViewController.m:

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

This delegate method is called when a link is selected. It simply requests UIApplication to open the URL, which will result in Safari being launched to open it.

But how can one add a link to the label displayed in the app? Simple, just change the implementation of loadShow: in section #5 so that the label displaying the show title is an NIAttributedLabel instead of a UILabel.

Replace the // 5 - Display the show title section with the following:

// 5 - Display the show title
NIAttributedLabel *titleLabel = [[NIAttributedLabel alloc] initWithFrame:CGRectMake(index * CGRectGetWidth(self.showsScrollView.bounds), 40, CGRectGetWidth(self.showsScrollView.bounds), 40)];
titleLabel.text = showDict[@"title"];
titleLabel.backgroundColor = [UIColor clearColor];
titleLabel.linkColor = [UIColor redColor];
titleLabel.font = [UIFont systemFontOfSize:18];
titleLabel.textAlignment = NSTextAlignmentCenter;
[titleLabel addLink: [NSURL URLWithString:showDict[@"url"]] range:NSMakeRange(0, titleLabel.text.length)];
titleLabel.delegate = self;

The main difference is the existence of linkColor, and addLink:. It’s also important to set the label’s delegate to self, which represents the current instance of the ViewController.

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

Where To Go From Here?

You can download the completed project from here.

Now that you know the basics of using CocoaPods, you can read through the CocoaPods Guides to learn the finer details of using CocoaPods, including how to create your own pod spec and submit it to the official repository.

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.
  • CorePlot: Graphing and plotting framework.
  • MagicalRecord: Super Awesome Easy Fetching for Core Data 1!!!11!!!!1!
  • MBProgressHUD: An activity indicator that can be added to your views.
  • Nimbus: The iOS framework that grows only as fast as its documentation.

You should also check out the trakt API. It’s well-documented, and you can do a lot of things with it.

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 look forward to reading your comments in the forums.

Know of another useful library? Tell us about it! Have you created a pod spec? Let us know about that too!

Joshua Greene

Joshua Greene is a full-time iOS Developer working at App-Order in Las Vegas, NV. When he's not slinging code, he enjoys martial arts, Netflix, and spending time with his wonderful wife and daughter. You can reach him by email or on Twitter.

User Comments

56 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
  • Hi Joshua,

    when I add the SSH Toolkit and Nimbus via terminal I get the following message:

    Downloading dependencies
    Installing AFNetworking 2.2.1 (was 2.2.1)
    Installing Nimbus (1.2.0)
    Installing SSToolkit (1.0.4)
    [!] Pod::Executable
    set -e
    echo "This Pod relies on the removed \`pre_install\` or \`post_install\` hooks and therefore will no longer continue to work. Please try updating to the latest version of this Pod or updating the Pod specification. See http://blog.cocoapods.org/CocoaPods-Trunk/ for more details." && exit 1

    This Pod relies on the removed `pre_install` or `post_install` hooks and therefore will no longer continue to work. Please try updating to the latest version of this Pod or updating the Pod specification. See http://blog.cocoapods.org/CocoaPods-Trunk/ for more details.

    Cheers, Martin
    mlanius
  • Had the same problem as mlanius. To fix it just change in the PodFile
    pod 'SSToolkit', '1.0.4' to
    pod 'SSToolkit', '2.0.0'

    You can check out the most recent version on the CocoaPods website.

    BTW nice tutorial Joshua.

    Cheers
    Dragon64
  • Kudos, Joshua, for an EXCELLENT tutorial. I appreciate the fact that oftentimes, examples are a "snapshot in time" of a particular combination of libraries and versions, and as such, expect there to be some bumps in the road. We can all argue that there should be more detail, retroactive updates to examples, etc., but c'mon people - we're programmers - presumably capable of figuring this stuff out. I appreciate the constructive comments and insights - this is how we learn. It's not always helpful to get everything delivered on a silver platter. Just sayin'. Old School.

    "The best coding tool you have is between your ears." [paraphrased from and apologies to Michael Abrash...]
    BKKFlynnsta
  • For me, i needed to add the path to the podfile, at the top, like so:

    xcodeproj '/Users/Matan/Documents/ObjectiveC/XcodeBiuldingProjects/ShowTracker/ShowTracker.xcodeproj

    Before the line: "target "ShowTracker" do".
    yosihashamen
  • Hi Joshua, It's a nice tutorial and have me appropriately to install cocoa pods. However I am struck in the middle. I have completed installations and coding successfully upto displaying the title of the show, but when I am compile and run the project it is showing an error,

    Use of undeclared identifier "SSToolkitDefines".

    And later I found that all the constants that are declared in SSToolkitDefines.h are displaying error.

    Can anyone help what could be the solution to this problem.
    rameswar54
  • You are f*ing f*! I meant it in a good way.. Actually admiring the way you have these pictures like Yeah! to keep us going. You are f*ing maan!
    Satay
  • If anyone else is getting the following error while installing CocoaPods:

    ERROR: Error installing cocoapods:
    cocoapods requires cocoapods-try (~> 0.3.0)


    See if this helps you out:
    http://stackoverflow.com/questions/2477 ... -cocoapods
    benmagos
[ 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 July: Facebook Pop Tech Talk!

Sign Up - July

RWDevCon Conference?

We are considering having an official raywenderlich.com conference called RWDevCon in DC in early 2015.

The conference would be focused on high quality Swift/iOS 8 technical content, and connecting as a community.

Would this be something you'd be interested in?

    Loading ... Loading ...

Our Books

Our Team

Tutorial Team

... 49 total!

Update Team

Editorial Team

... 23 total!

Code Team

  • Orta Therox

... 1 total!

Translation Team

  • Heejun Han
  • Przemysław Rembelski
  • Jiyeon Seo

... 33 total!

Subject Matter Experts

... 4 total!