About this book

RestKit is an iOS framework for streamlining communication with web services, and it relies on the AFNetworking library that is used by thousands of app developers. It has an interface that is elegant and well designed, and it provides a powerful object-mapping engine that integrates well with the CoreData database. RestKit for iOS will teach you everything from loading a simple list of objects to creating a fully-featured app.

RestKit for iOS delivers constructive tools and insights into app development that will benefit any app developer. The book starts with a simple example and then moves on to more complex ones as your knowledge increases. By the end of the guide, you will be able to build a fully-featured app that uses RESTful web services and performs CRUD object manipulation.

RestKit for iOS will provide you with all the information you need to boost the development process of both simple and complex apps. Once you have executed a simple example and reviewed the basic theory, you will move on to more advanced concepts with descriptions of real-life scenarios and how to overcome bottlenecks. RestKit for iOS is full of real-life examples that show you how to simplify data loading, basic and advanced object mapping, metadata mapping, and routing. This book also teaches you about routing, RESTful object manipulation and synchronization, integration with the user interface, and caching

Publication date:
September 2013
Publisher
Packt
Pages
118
ISBN
9781782163701

 

Chapter 1. Getting Started

RestKit is a well-known framework without much documentation. Even with its reference manual and accompanying blog posts, not much has been covered, especially in terms of practical usage. Not every developer has the time to indulge in figuring out RestKit on his own before starting a time-constrained project. Sounds familiar?

Learning a new framework comes with its required steps. Before jumping into RestKit libraries, object mapping fundamentals, and data modeling, we need to make the proper introductions. This chapter will start with a simple usage example to warm up the crowd, before elaborating on the whats, whys, and hows of RestKit, in addition to its components. This compact introduction will already have demonstrated how select real-life examples can provide the required insight into the world of RestKit.

As you know, nothing in this world is perfect, and so are REST APIs. Every single API I worked with has its own glitches and bottlenecks. So, we will discuss some of the possible bottlenecks with APIs, how to overcome them, and we will experience a few in the API that we will use in the example.

 

Simple usage example


We can show a simple example of using RestKit by loading this kind of JSON:

[
  {
    "hostname": "sandbox.mongohq.com",  
    "name": "Test",  
    "plan": "Sandbox",
    "port": 10097,
    "shared": true  
  },
  {
    "hostname": "second.mongohq.com",  
    "name": "Second",  
    "plan": "Second",
    "port": 10097,
    "shared": true  
  }
]

And mapping it to a list of database objects:

@interface MDatabase : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *plan;
@property (nonatomic, strong) NSString *hostname;
@property (nonatomic, strong) NSNumber *port;
@end

Would be just invoking this piece of code:

RKObjectManager *manager = [RKObjectManager sharedManager];
[manager getObjectsAtPath:@"/databases" parameters:nil 
                  success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) 
{
    NSLog(@"Loaded databases: %@", [mappingResult array]);
} 
                failure:^(RKObjectRequestOperation *operation, NSError *error) 
{
    NSLog(@"Error on loading: %@", [error localizedDescription])
}];

As we see here, not much code. Of course, we will need some additional pre-setup to get this working, which we will cover later in this and the following chapter.

 

So what is RestKit?


"I once told an Objective-C joke, but nobody got the message."

Many of us are being introduced with the concept of networking in iOS and Objective-C by playing with NSURLConnection. It's a base class for making any outgoing HTTP connection. However, after using it several times in a project, you may start building your personal networking library, of course, under the hood; it's still the same NSURLConnection, but most likely, you would write your own wrappers for it with additional bells and whistles. In addition, while using it, you may experience different bugs, glitches, and performance issues. Also, while using it in different projects, you will probably modify the code, find and fix bugs in it, but you will experience a lot of hassles in maintaining a "one codebase" of such a homegrown library.

So my personal opinion is "Don't re-invent the wheel. Don't re-invent a bicycle. Unless you really need a very custom one, with a big front wheel (as shown in the next figure), which might happen only in 1 percent of cases."

Try to keep things simple. In our case, the working bicycle can be a library called AFNetworking, which is a very useful networking library for iOS and OS X. The framework is built on top of Apple's Foundation technologies such as NSURLConnection, NSOperation, and others. It has a modular architecture and a well-designed API, which is quite easy to use. While being simple and easy-to-use, it also supports block-based programming, file uploads, reachability, and lots of other useful tasks that any developer might need. It is used by thousands of app developers and is highly maintained.

Now RestKit itself is a framework for implementing clients of RESTful web services, and feels like AFNetworking is on steroids. It provides a simple interface to build network communication while mapping HTTP requests and responses. Additionally, it has a powerful object-mapping engine that seamlessly integrates with the Core Data. It has an elegant, well-designed, fully documented, and fully tested set of APIs magically allowing easy accessing and modeling RESTful resources.

It greatly simplifies the application development by providing a solution by interconnecting your application's data model with JSON or XML documents, provided by a web service you are communicating with. It shifts a lot of logic for making requests and mapping the data to the library, thus giving a developer the ability to keep an application code simpler and less cluttered. It speeds up the development process by giving solutions and patterns for common problems that one can face, such as working with Core Data and doing network-related coding.

When thinking whether to use a RestKit library in your next project, consider a few things:

  • Not every API will work with a RestKit library, especially the ones that follow the RPC (Remote Procedure Call) paradigm.

  • Your backend web-service API is more or less RESTful. You can describe interactions with your web application with the CRUD (Create, Read, Update, and Delete) operations on resources.

  • "Don't use a sledgehammer to crack a nut." If you just need a one-time request to a simple JSON in your app, reconsider using a RestKit library in favor of using something simple, such as AFNetworking.

  • While developing a library, think if you can minimize a footprint of it and exclude dependencies on big third-party libraries, such as RestKit.

 

Why RestKit?


We can compare RestKit to some other popular or similar solutions:

As we can see here, there are numerous libraries that do mapping of objects, or simplify the development by making hidden requests while fetching data from Core Data. Some of them are quite interesting to check and study—depending on a type of project one is doing. The downside of the earlier-mentioned libraries is that these solutions are relatively new, still in active development, or quite complex to set up.

 

RestKit components


RestKit ships as a single framework to the end user, but internally, it is composed by several interconnected components. We have described the parts of RestKit in the following list:

  • Object manager: One of the main components of a RestKit library. It works as a bridge between it and other components, and provides one-line methods for "getting the work done".

  • Object mapping: One of the main functional components of RestKit. The object mapping system enables a mechanism to express the transformation of objects between representations using KVC and the dynamic features of the Objective-C runtime.

  • Networking: This feature integrates object mapping with the HTTP network layer provided by AFNetworking. It has the ability to make serialization and deserialization of JSON/XML objects, bind mapping descriptions with HTTP requests and responses, generate URLs from path patterns, route, and serialize local objects into HTTP parameters.

  • Core Data: This component is responsible for the integration between the object mapping and networking components and Apple's Core Data framework. Mostly, it includes a special Core-Data-related implementation of some parts from the object mapping and networking layers, and also specific functionality for the relationship connection of managed objects.

  • Search: Specific parts related to Core Data components that are responsible for indexing and searching of managed objects. It includes a tokenizer, indexer, and API for generating search predicates to be used while querying indexed objects.

  • Testing: Helps developing unit tests with ease by providing helpers and mocking abilities for RestKit components. Also includes helpers to build and use test fixtures.

 

How it works?


We can describe how you interact with RestKit by looking at the following sample sequence diagram for getting data:

RestKit usage sequence diagram

When you, as a Caller, wish to get data from a Remote web service, you ask for it on RestKit. It then decides on a strategy and gets the paths and mapping information by checking a configuration for the particular type of objects that you want. RestKit uses AFNetworking under the hood to do the actual data retrieving from the Remote and parsing in to NSDictionary or NSArray. AFNetworking itself checks with NSURLCache if it should make a request again, or use the cache. (We'll discuss this in detail in Chapter 4, Advanced Stuff in the HTTP Caching section). AFNetworking then gives back the response to a RestKit, along with all additional information, which were gathered during the "request-response-parse sequence".

If you're not using Core Data for this type of objects (we can call it "In-Memory object"), RestKit creates new instances of the object, and maps a response data to it. It then returns the object(s) back to the Caller.

Now if you are using Core Data, and the object is a Managed object, RestKit will first check with the Core Data if it already has an object with a similar ID. It will also check if the object in response has a deleted flag. It will then do the mapping and update/delete the particular object, and check how to deal with orphan objects. At the end, it will return the resultant objects to the user. Core Data itself will notify all its observers via Key Value Observing (KVO) about the changes.

 

Adding RestKit and libraries


It used to be quite hard to add third-party libraries to Mac or iOS projects. You would have to deal with all sorts of dependencies, configuring special behavior, and spend days on integrating big libraries to your project.

This was not an issue for some other platforms. C# with Visual Studio has had the NuGet package manager for quite a while. And Ruby has its RubyGems with Bundler. Recently, the situation has changed for iOS and Mac app developers. Highly inspired by Ruby's Bundler, a new package manager for us arrived—CocoaPods. It is the best way to manage library discrepancies in Objective-C projects.

Now in comparison to RubyGems' Gemfile, CocoaPods uses a so-called Podfile, where a developer lists the names of a library he is willing to use and his version. By the way, it uses Podspec files to describe how a particular library should be integrated with your project. Actually, CocoaPods is using an Xcode Workspace for the integration between your project and a Pods project, which includes all third-party libraries.

If you have never installed a CocoaPods package manager before, let's do so! You start by executing the following commands:

$ [sudo] gem install cocoapods
$ pod setup

The pod is an executable package, which is installed with CocoaPods.

Next, we want to search the Spec repository using the following command to get, which version of RestKit is available as of today:

$ pod search RestKit

The result might look like this:

bash-3.2$ pod search RestKit


-> RestKit (0.20.3)
   RestKit is a framework for consuming and modeling RESTful web resources on iOS and OS X.
   pod 'RestKit', '~> 0.20.3'
   - Homepage: http://www.restkit.org
   - Source:   https://github.com/RestKit/RestKit.git
   - Versions: 0.20.3, 0.20.2, 0.20.1, 0.20.0, 0.20.0-rc1, 0.20.0-pre6, 0.20.0pre5, 0.20.0-pre4, 0.20.0-pre3, 0.20.0-pre2, 0.20.0-pre1, 0.10.3, 0.10.2, 0.10.1, 0.10.0 [master repo]
   - Sub specs:
     - RestKit/Core (0.20.3)
     - RestKit/ObjectMapping (0.20.3)
     - RestKit/Network (0.20.3)
     - RestKit/CoreData (0.20.3)
     - RestKit/Testing (0.20.3)
     - RestKit/Search (0.20.3)
     - RestKit/Support (0.20.3) 

In addition, you can also hit your browser to view the official website of CocoaPods (http://CocoaPods.org), where you will be able to use the web-based search and get more info on the available packages and CocoaPods news.

Now change to the directory of your Xcode project, and create (or edit) your Podfile with your favorite text editor and add RestKit (or create it using Xcode if you like):

$ cd /path/to/MyProject
$ nano Podfile

# Platform - ios, mac
platform :ios, '5.1'

# List of libraries to install
pod 'RestKit', '~> 0.20.3'

# Testing and Search are optional components
pod 'RestKit/Testing'
pod 'RestKit/Search'

By specifying the platform and its version we want to be sure that all libraries and dependencies we are using will smoothly run on the target.

Now with RestKit, ~> 0.20.3 in the previous command-line snippet, means we want to use at least Version 0.20.3 or advanced in the range of 0.20.X. If you skip specifying the version, CocoaPods will install the latest.

Tip

If you enter pod 'RestKit', :head, CocoaPods will install the library from the latest sources. Or you can provide your source path (if you forked it, for example) by entering the following line of code:

pod  'RestKit',  :git  =>    'https://github.com/RestKit/RestKit.git'

Now it's time to install it in your project. Just run the following command:

$ pod install

And you will probably see the following output:

bash-3.2$ pod install
Analyzing dependencies
Downloading dependencies
Installing AFNetworking (1.3.2)
Installing RestKit (0.20.3)
Installing SOCKit (1.1)
Installing TransitionKit (1.1.1)
Generating Pods project
Integrating client project 

CocoaPods downloads the third-party code and creates a new workspace—a file named YourProject.xcworkspace. From now on, you will use the .xcworkspace file to open your project in Xcode.

As you can also see, CocoaPods will install some libraries (such as SOCKit) that we did not ask for. They are dependencies of a RestKit library, and are specified in a RestKit's Podspec file.

Tip

Run pod update to fetch and install the latest versions of packages. In addition, running [sudo] gem update cocoapods will update the CocoaPods manager to the latest version.

Once again, do not forget that you need to use workspace from now on. So to open your project in Xcode, one can shoot the following command in the terminal:

$ open MyProject.xcworkspace

The following screenshot shows the sample project tree in the workspace after installing RestKit and few other libraries.

Project tree in Xcode after installing a few libraries using CocoaPods

Add the following line to your .pch file (it is a precompiled header file, which is automatically included in all source files of your project) to be able to use all RestKit components through your code:

#import <RestKit/RestKit.h>

Tip

If you've worked previously with RestKit 0.10, you should know that with the release of Version 0.20, it had major API changes, which are backwards incompatible. Consider checking RestKit's Wiki article Upgrading from v0.10.x to v0.20.0 in the following link:

https://github.com/RestKit/RestKit/wiki/Upgrading-from-v0.10.x-to-v0.20.0

Please note that if your installation fails, it may be because you are installing with a version of Git lower than what CocoaPods is expecting. Please ensure that you are running Git 1.8.0 or higher by executing git --version. You can get a full picture of the installation details by executing pod install --verbose.

If you want to install RestKit as a Git submodule or from a release package, the best way is to follow the instructions on RestKit's Wiki article Installing RestKit v0.20.x as a Git Submodule in the following link:

https://github.com/RestKit/RestKit/wiki/Installing-RestKit-v0.20.x-as-a-Git-Submodule

 

MongoHQ – a MongoDB in clouds


"Three DBAs walk into a NoSQL bar. A little while later they walk out because they couldn't find a table."

For our examples in this book, we will use a service in a cloud called MongoHQ. It's the most powerful platform for MongoDB hosting. Apart from providing one of the best MongoDB hosting solutions, they recently released a beta REST API for accessing their services. This is quite interesting for using in mobile clients, as accessing directly a MongoDB server is not the easiest of tasks.

Note

MongoDB (from "humongous") is an open source document database and the leading NoSQL database.

http://en.wikipedia.org/wiki/MongoDB

MongoDB's main difference from "classical" relational databases is that instead of storing data in tables, MongoDB stores structured data as JSON-like documents with dynamic schemas (MongoDB calls the format BSON), making the integration of data in certain types of applications easier and faster.

The nice part about it is if you are not sure beforehand on what your data will look like, the document-type databases are a weapon of choice. You can change the structure with ease almost on the fly; you don't need to run any migration scripts. This greatly simplifies development in the early stages and/or the startup phase.

 

Trying basic stuff


For our basic example, we will check the status of MongoHQ servers. For showing statuses, MongoHQ uses the Stashboard web app, which you can access at http://status.mongohq.com.

The following screenshot (cropped) shows the status page of the MongoHQ servers:

An example of Stashboard App usage is Twilio, with the status page at http://status.twilio.com, and the Status API endpoint at http://status.twilio.com/api/v1/.

The documentation for a Stashboard API can be found at https://stashboard.readthedocs.org/en/latest/restapi.html.

To keep going, first let's define our StatusItem object, looking at a possible data we will need:

// StatusItem.h
@interface StatusItem : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *itemDescription;
@property (nonatomic, strong) NSDate *timestamp;
@property (nonatomic, strong) NSString *eventMessage;
@property (nonatomic, strong) NSString *statusName;
@property (nonatomic, strong) NSString *imageUrl;

@end

// StatusItem.m
@implementation StatusItem

// for better debug information output
- (NSString *)description
{
    return [NSString stringWithFormat:@"%@ - %@", 
         self.name, self.eventMessage];
}
@end

Now let's try and load the current statuses:

// Method to load the status items
- (void)refresh
{
    // Setup the object mapping
    RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[StatusItem class]];
    // From JSON -> To property
    [mapping addAttributeMappingsFromDictionary:@{
     @"name"                       : @"name",
     @"description"                : @"itemDescription",
     @"current-event.status.name"  : @"statusName",
     @"current-event.status.image" : @"imageUrl",
     @"current-event.timestamp"    : @"timestamp",
     @"current-event.message"      : @"eventMessage",
     }];
    
    // Define the response mapping
    // Map response with any status code in 2xx
    NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful);
    
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor  
      responseDescriptorWithMapping:mapping
                             method:RKRequestMethodAny 
                        pathPattern:@"/api/v1/services" 
                            keyPath:@"services" 
                        statusCodes:statusCodes];
    
    // Prepare the request operation
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://status.twilio.com/api/v1/services"]];
    RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]];
    
    // Set on completion and on error blocks
    [operation 
      setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *result) 
    {
        NSLog(@"Loaded items: %@", [result array]);
    } 
                           failure:^(RKObjectRequestOperation *operation, NSError *error) 
    {
        NSLog(@"Failed with error: %@", [error localizedDescription]);        
    }];

    [operation start]; //Fire the request
}

Tip

Downloading the example code

You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

In this example, we are using a RKObjectRequestOperation object. It performs a base operation in all RestKit requests. Even for more high-end user-friendly methods, it will be run under the hood.

When we run the example, we see the debugger output:

Loaded items: (
    "Aaron - All systems operational.",
    "Alex - Alex is operational.",
    "Arrow - All databases accessible and operating normally."
)

If we put it in a table view (we will discuss about integrating RestKit and user interface best practices in Chapter 2, Modeling and Loading Remote Objects), it will look like the next screenshot:

Status of DBs

 

Object mapping fundamentals


The object mapping engine of a RestKit is built on the KVC informal protocol, which is foundational to numerous Cocoa technologies, such as Key-Value observing, bindings, and Core Data. After the response body was parsed, RestKit relies on KVC to identify the content that can be mapped and dynamically updates the attributes and relationships of your local domain objects with the appropriate content. Before diving into the details of RestKit's object mapping system, be sure to get familiar with Apple's Key-Value Coding and go through its programming guide at the following link:

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/KeyValueCoding/Articles/KeyValueCoding.html

Using a highly dynamic Objective-C runtime, RestKit examines the type of source and destination properties of object and performs appropriate type transformations. For example, when a JSON is parsed and a source key path created_at (with a string content) is configured to be mapped to a destination key path, creationDate(this is an NSDate property on a target object), RestKit will transform the date from a string into an NSDate property using an NSDateFormatter. The other transformations can be string to number and vice versa, or a developer can build his own transformation strategy, if needed.

The mapper also fully supports relationship mappings, where nested to-one or to-many child objects are mapped recursively.

 

Data modeling


Let's discuss our basic example. We were loading data from the Status API endpoint, http://status.twilio.com/api/v1/services. If we visit this URL with our web browser, we see a JSON output similar to the following code:

{
  "services": [
    {
      "current-event": {
        "informational": false,
        "message": "All systems operational.",
        "sid": "ag5tb25nb2hxLXN0YXR1c3INCxIFRXZlbnQYi-gUDA",
        "status": {
          "description": "The service is up",
          "id": "up",
          "image": "http:\/\/status.mongohq.com\/images\/status\/tick-circle.png",
          "level": "NORMAL",
          "name": "Up",
          "url": "http:\/\/status.mongohq.com\/api\/v1\/statuses\/up"
        },
        "timestamp": "Wed, 13 Mar 2013 18:10:21 GMT",
        "url": "http:\/\/status.mongohq.com\/api\/v1\/services\/aaron\/events\/ag5tb25nb2hxLXN0YXR1c3INCxIFRXZlbnQYi-gUDA"
      },
      "description": "MongoDB Server",
      "id": "aaron",
      "name": "Aaron",
      "url": "http:\/\/status.mongohq.com\/api\/v1\/services\/aaron"
    },
 {
      "current-event": {
        "informational": false,
        "message": "Alex is operational.",
        "sid": "ag5tb25nb2hxLXN0YXR1c3INCxIFRXZlbnQY0coWDA",
        "status": {
          "description": "The service is up",
          "id": "up",
          "image": "http:\/\/status.mongohq.com\/images\/status\/tick-circle.png",
          "level": "NORMAL",
          "name": "Up",
          "url": "http:\/\/status.mongohq.com\/api\/v1\/statuses\/up"
        },
        "timestamp": "Sat, 20 Apr 2013 15:23:20 GMT",
        "url": "http:\/\/status.mongohq.com\/api\/v1\/services\/alex\/events\/ag5tb25nb2hxLXN0YXR1c3INCxIFRXZlbnQY0coWDA"
      },
      "description": "A sandbox environment for MongoHQ.",
      "id": "alex",
      "name": "Alex",
      "url": "http:\/\/status.mongohq.com\/api\/v1\/services\/alex"
    }
  ]
}

When RestKit loads this JSON, first of all it parses it to the NSDictionary or NSArray response object. Then, looking at the mapping we provided, it will make a KVC query on the response object. If the value is found, it will check its type as well as the type of our target property. If the types don't match, RestKit will try to transform it. If one of such transformations is a timestamp mapping, which in JSON is a string, and on the target property it is NSDate, RestKit will parse the JSON string in to NSDate with default (or custom provided) NSDate formatter(s). If the parsing is successful, it will update our destination property.

Let's check our mapping again line by line:

We create the mapping for the StatusItem class:

RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[StatusItem class]];

We tell how to map JSON objects to properties by providing an NSDictionary to the addAttributeMappingsFromDictionary method:

[mapping addAttributeMappingsFromDictionary:@{

Map name from JSON to the property name:

@"name": @"name",

We can't use some names for properties, such as id or description. So, we named description from JSON as itemDescription property:

@"description": @"itemDescription",

Here, RestKit will use KVC to get the value (asking name from status from current-event):

@"current-event.status.name" : @"statusName",
@"current-event.status.image": @"imageUrl",

It will parse the timestamp string in JSON and store it as an NSDate property:

@"current-event.timestamp": @"timestamp",

And here again it will use KVC to get message and store it in the eventMessage property:

@"current-event.message": @"eventMessage",
}];

Now that wasn't hard, was it?

 

Summary


In this chapter, we discovered what is RestKit, its components, and why it's good to keep things simple. We discovered a CocoaPods library manager and installed RestKit through it. We covered basic data modeling techniques, and tried a simple example by sending a request to a status page and getting parsed and mapped objects in response.

The next chapter will cover more about how to configure the RestKit, do the RESTful object manipulation, and integrate the code with our user interface, in detail. So let's move on!

About the Author

  • Taras Kalapun

    Taras Kalapun has more than 10 years experience as a Software Developer and Consultant in Mobile and Web. His background spans numerous technologies, programming languages, and databases. He was involved in developing more than 100 iOS projects and web services, as well as project management activities. In addition, he managed teams of software developers who all wanted to kill him. Through his mentoring, tech leading, troubleshooting, and code reviewing, he discovered that teaching by example resulted in more effective software development. A method he supplemented with, "Stop trying to reinvent the wheel"—a favorite phrase he used to tell young software developers. He has worked at a number of IT companies across Europe including Ukrtelecom, a national Ukrainian telecommunication company; Ciklum, a Dutch outstuffing company headquartered in Ukraine; and Xaton, an Amsterdam software development company, in addition to freelance projects. Occasionally he publishes small how-to articles on solving development problems and impedances on his blog, http://kalapun.com, some of which progressed to the development of this book.

    Browse publications by this author
Book Title
Access this book, plus 7,500 other titles for FREE
Access now