RestKit is an amazing Objective-C framework for iOS that aims to make interacting with RESTful web services simple, fast and fun. As said on its homepage:
It combines a clean, simple HTTP request/response API with a powerful object mapping system that reduces the amount of code you need to write to get stuff done.
RestKit provides several components:
- An HTTP client component based on
NSURLConnection. It’s not as feature-packed as ASIHTTPRequest1, but it does its part very well in most cases. It supports
HTTP AUTH, multi-part, etc. It even provides a request queue to manage the HTTP requests(mostly implicitly), making them more memory and bandwidth efficient.
- A powerful but elegant object mapping system, which uses idiomatic key-value coding mechanism to define and implement the round-trip transformation between
JSON2 string and native Objective-C class. Well, the magic behind it is called SOCKit3.
- A persistent layer built on top of the object mapping system, fully integrated with CoreData. Can be used as app’s primary data storage or just local cache.
- Miscellaneous helpers for better life. Reachability, database seeding, API environments switching, etc.
Other than making another almighty monster its creators focus on the remote-local object (can be transient or persistent through CoreData) mapping. They made it through the ‘common things simple, others possible’ philosophy, which I always love.
RestKit has some documentations but not very well organized. Maybe it’s the biggest problem for beginners. So I’d like to list below some most useful solution recipes I’ve used in real world project, updated progressively.
**WARNING**: it will be incredibly long anyway.
RestKit provides two ways to set up the RestKit client:
RKObjectManager. If you want to manually handle the return data you should use
RKClient. Otherwise, if you want to use the RestKit object mapping system, then
RKObjectManager is the one.
RestKit uses a convenient convention: the first initialized client object becomes a singleton and can be referenced by
[RKClient sharedClient] or
[RKObjectManager sharedManager] correspondingly.
In real world we usually have more than one base URLs, say, one for product environment, the second for testing and third for developing. The base URL can be easily changed globally:
Note that change base URL while app is running may bring some side effects. See the API document for detail.
RKClient acts just like a plain asynchronous HTTP client. You can send any HTTP request through its intuitive interface:
RKObjectManager you’ll map the web resources to local Objective-C objects, so you need not (and cannot) handle the return data explicitly. Instead you should handle data through the mapping system, which will be discussed below.
Modeling and Mapping
Now the object mapping system. Let’s start with the best practice in RESTful API backed mobile app development:
- Analyze the business and make abstraction.
- Design the RESTful API spec based on the first step, including all call endpoints, parameters and returning data in JSON format.
- Mapping the API spec to native code in designated mobile platform.
Assuming we have a simple API named
users/login, accepting POST request with 2 parameters:
password, doing login check, and returning a encrypted access
token and corresponding
user object. And as a global convention we encapsulate the payload as
response section in a JSON string which also contains a
meta section for system level info such as status code and error message. So here it looks like:
It’s simple but not trivial, and very representative. What will the mapping work? Have a look at the code first:
Line 1-35. Firstly we defined all needed model classes: fundamental ones first, ones that contain them next. Just follow the nature of the data structure within the API’s response data.
Line 51-56. Use instances of
RKObjectMapping class to define object mappings. Simple mappings are self explained. Note that
RKObjectMapping provides several different
mapXXX methods to suit different use cases. The key path in mapping definition fully follows Cocoa’s key path style (also support collection operators). Check its document and Apple’s Key Value Coding Guide for detail.
Line 58-61. Complex object mappings are defined by
mapKeyPath:toRelationship:withMapping: or similar methods. They map some key path to pre-defined object mappings. As seen in the code, the mapping to class
UsersLogin contains simple mapping (line 59) and relationship mappings (line 60-61).
loadObjectsAtResourcePath:objectMapping:delegate: method to do these steps in order: combine resource path with the global
BaseURL (configured within the
RKObjectManager singleton), load resource from web services, parse return data, transform to local objects according to pre-defined
RKObjectMapping instance, at last call the delegate to handle result.
Line 72-80. Delegate methods
didFailWithError (required) are called after the object mapping process. Normally fetch the result object and do whatever you want.
The previous code list is neat except one part. Note line 64-66, in which we hard-code the API endpoint and parameters. In our
login scenario it may not be a big problem, but for highly reused objects, repeatedly constructing
DELETE URLs by hand could be real pain in the ass. How about more object-oriented and more elegant way, just like the routing system in Ruby on Rails?
RestKit is most suitable for developers who has RoR background because of its Routing system which is highly alike to RoR’s, but built on Cocoa’s idiomatic key-value coding way. Here is the code sample:
Line 4 set the default route of
User class, which means when you call object manager’s
deleteObject methods the requests will go to
@"/users/:id". This is a colon coded endpoint and what is after the colon is the name of a method in the route class, whose return value will replace the colon part.
Line 5 set a special route for
postObject method, which will override the setting in default route.
Line 10 requests
@"/users" with HTTP
POST method and RestKit will transform
me object into post data form as the way defined in object mapper of class User.
Line 14 first call
[sb2nuke id] method to get the value and replace
:id with it, then requests
@"/users/13" with HTTP
DELETE method, which (should) remove the user object with id 13 from the server.
So you see, RestKit provides very flexible tools for RESTful web services integration: you can use the network layer and do all data mapping by hand, or you can use the object mapping to do it completely within local object system, or you can tuning it in some intermediate way. No matter which solution you choose remember to align the protocol between the server and client side, and don’t forget to verify them to the Android platform if necessary (there is no RestKit over there for now -_-).
Thus we’ve completed the first part of this introduction guide. Below we will discuss some facilities bundled in RestKit to make our life better.
The Request Queue
Request queue is the most important support player under the hood.
RKRequestQueue is behind nearly all network access within RestKit and provides elegant solution for critical memory and bandwidth problems.
RKRequestQueue wraps memory management within RestKit framework so you’ll never see any
RKResponse instances. It let us developers focus on the business with very little concern about the memory management.
RKRequestQueue also provides seamless integration with Reachability API (in iOS System Configuration framework), pooling all requests when network is unavailable, and limiting concurrent requests when network becomes reachable to prevent overburden as well.
All the amazing features described above are working without knowing, and maybe the only visible part of
RKRequestQueue is its request lifecycle management feature, by which you can cancel ongoing requests to prevent wasting the bandwidth. This is a common situation in mobile apps that when some user action generates a bunch of network requests and the following action actually makes those requests useless (e.g. the view for previous action is dismissed by the later action). By using
RKRequestQueue we can do it very easily by its
cancelRequestsWithDelegate: and cancelAllRequests:` methods. And remember that whether and when to call them is fully determined by developers so you can choose the strategy wisely according to the different scenarios. Here is the simplest sample:
cancelRequestsWithDelegate: method cancel all requests that current controller is delegate for. If there are no one processing it’ll do nothing.
The last but not least. What
[RKRequestQueue sharedQueue] returns is the default queue which created automatically when the RestKit client initialized. In most real world apps it’s not enough. For example we may need a queue to handle special resource intensive tasks in a background thread, such as data uploading/downloading, while the default queue keep working for responding user actions. It’s easy:
Reachability is the problem all mobile apps have to face and of course iOS provides solution for that, well, sort of. The problem is:
SystemConfiguration framework) is implemented as low level C APIs and not so easy to use. Fortunately RestKit is bundled with a very straight-forward Objective-C wrapper for that, the
When RKClient (or RKObjectManager) is initialized with some base URL, RestKit automatically initializes an instance of RKReachabilityObserver targeted at the host specified in the base URL and can be accessed via
baseURLReachabilityObserver property. This observer also automatically registers
RKReachabilityStateChangedNotification events in the default notification center. So in most cases we can use it in very simple way:
Sending Multi-part Data
Sending multi-part data through HTTP requests is very common requirement and incredibly difficult in most programming languages. RestKit uses
RKParamsAttachment to handle that problem.
RKParams is the container that can hold any kinds of parameters. For simple data type it works just like a NSDictionary, and for multi-part data it can wrap
RKParamsAttachment objects. Both
RKParamsAttachment are MIME type friendly. The following self-explained code sample shows all:
iOS supported multi-tasking since 4.0 but it’s a highly restricted support and there are so many misconceptions among the users and even developers. I would strongly suggest Fraser Speirs’ excellent blog which explains all about iOS multi-tasking.
RestKit can seamlessly facilitate multi-tasking to prevent important long-time requests being interrupted by user switching out of the app. The key is the
backgroundPolicy property of
RKRequest which can be one of 4 enum values:
RKRequestBackgroundPolicyNone: the default value, do nothing for backgrounding;
RKRequestBackgroundPolicyCancel: cancel the request when app switches to background;
RKRequestBackgroundPolicyContinue: continue the request in background;
RKRequestBackgroundPolicyRequeue: place the request back to the queue for next activation.
So to make a request continue to work in background, just set its
backgroundPolicy property as below:
RestKit is a clean and elegant solution for iOS app to interact with RESTful web services. It encapsulates many everyday work into a tiny yet powerful framework and extremely easy to use. Suggest every iOS developers to give it a try.
- RestKit References (master branch)
- Tutorial: Introduction to RestKit
- Advanced RestKit Development
- RestKit Solution Recipes