Please also check out my other post on using Realm mobile database, a no thrills alternative to Core Data, with Mantle model framework + AFNetworking. With this delightful combination of software libraries you should be able to get your network and persistence layers up and running in no time. http://www.toptal.com/ios/simplifying-restful-api-use-and-data-persistence-on-ios-with-mantle-and-realm.
This tutorial is intended for intermediate iOS developers. It assumes basic understanding of Core Data. If you’re not yet familiar with this technology, I recommend that you take a look at this excellent introduction to Core Data by Adam Burkepile on Ray Wenderlich’s website.
We will be using Feedzilla news RESTful API. It provides, among other things, a list of current news articles in a number of categories. Our aim will be to fetch the list of current articles for a category of our choosing and then fetch information for each of those articles separately. Not only will we fetch that data, we will also persist it and present it in a nested table view.
This is where RESTKit, one of the most widely used iOS libraries, comes into play. It allows for seamless integration of an iOS app with a remote RESTful API. After initial configuration RESTKit fetches data taking care of the network stuff and parses the results into either your custom classes or straight into Core Data. In this tutorial we will be focusing on the latter.
Feedzilla API overview
As mentioned in the introduction, Feedzilla news API provides a list of news articles in different categories such as World News, Music, Sports, Programming and many others. The list of categories is available at http://api.feedzilla.com/v1/categories.json . Though we will not use this API endpoint in our app directly, we need it to choose a category for which articles we’re about to fetch. Let’s assume we’re going to use the ‘Programming’ category, whose id is 16. Of course, you might as well choose any other category.
We will be fetching data in JSON format, though both the API and RESTKit itself support XML as well.
Now, the list of articles in category ‘Programming’ is available at http://api.feedzilla.com/v1/categories/16/articles.json . Quite simply, if you wish to get an article list for a different category you need to provide its id instead of the number 16 in the above url.
And here’s a sample JSON result for this enpoint.
As we can see, the resulting JSON consists of three fields: title, syndication_url and description, along with a nested array of articles.
Core Data model
Let’s start by creating an XCode project using the “Master-Detail Application” template. Please make sure the “Use Core Data” checkbox remains unchecked, as we’ll be setting up Core Data ourselves.
Now that we have an XCode project it’s time to create our Core Data model by going to File -> New -> File -> iOS -> Core Data and choosing Data Model.
Let’s call our model quite simply DataModel and press Create. Our new model should now appear in the project list:
Before we dwelve into the technicalities of setting up a Core Data model, let’s again have a look at the structure of the JSON that we’re eventually going to store in Core Data. It contains a nested array of articles and three additional simple fields. The question now is: how do we model this in Core Data? The answer lies in the relationship between the two entities: the article list and the article itself. In a manner similar to relational databases, we might model the relationship between an article list and articles it contains as one-to-many, since an article list contains multiple articles, while a single article belongs to exactly one article list. To sum up, we are going to create a data model containing two entities: the article list and a relationship between them.
Let’s double click the DataModel.xcdatamodeld to start editing.
We need to add two entities by pressing the Add Entity button (1). After renaming them to Article and ArticleList (2) it’s time to start adding attributes (3). Let’s add three attributes to ArticleList: article_description, title and url — all of String type. Now let’s define the attributes of the entity Article as: publish_date, source, source_url, summary, title and url — again, all of them strings except for publish_date which will be of type Date. Now we can change the editor style by pressing the button denoted as (4) in the figure above. The result should be similar to this:
What we have here are two entities ArticleList and Article. If we compare them to our JSON we can clearly identify the corresponding attributes. The names of Article’s attributes match exactly the attributes in the response JSON, while the names of ArticleList’s attributes differ slightly from those in the JSON. This is on purpose to illustrate how attributes are mapped, as we’ll see later on during RESTKit configuration.
What we’re missing at this point is the aforementioned relationship between the two entities. Let’s revert to the previous editor style and add a relationship between ArticleList and Article.
After choosing ArticleList (1) we add a new relationship by pressing the ‘+’ button in Relationships section (2). Let’s name this new relationship articles (3) and set the destination of this new relationship to Article (4). Lastly, we need to change the type of it to To Many (5). Now let’s again change the editor style to graphical.
We can see that ArticleList entity remains in a to-many relationship with Article. In other words, article list contains multiple articles. In this very model the relationship in the other direction, that is from Article to ArticleList is undefined. Though we know that a single article belongs exactly to one list, this to-one relationship from Article to ArticleList is not modelled here, as it’s not necessary. All we need to know is what articles belong to a given list and we have just created a data model to store this information.
Now that our Core Data model has been defined we can generate a model file for each entity. By going to File -> New -> File -> iOS -> Core Data and choosing NSManagedObject subclass we can automatically create Core Data model files. After pressing Next we choose our data model, then again click Next and then select the entities for which files we’d like to generate:
Click through this and the next dialogue to save our newly created files. They should now appear in the project list:
Let’s have a closer look at them. What is interesting to us is that entity attributes have been declared as properties in .h files. Now if we look at the ArticleList.h file specifically, we’ll see that in addition to properties mirroring attributes of String type, there’s one more property of type NSSet called articles. This property will hold the articles that belong to the article list. The to-many relationship has been declared here as a property of type NSSet.
Installing and initializing RESTKit
The easiest way to install RESTKit in a project is to use CocoaPods. Details can be found on RESTKit Github page. Once the RESTKit pod has been installed, let’s open the project’s newly created workspace file. We should now be able to see RESTKit library installed with a few additional libraries such as AFNetworking.
Having installed RESTKit it’s time to initialize it. The best place to do this is the application delegate. And so, let’s add the following two import statements to the AppDelegate.m file:
We’ll place RESTKit configuration code in application:didFinishLaunchingWithOptions: method just above return YES; statement:
First off, we need to initialize RESTKit’s object manager with the base URL of the API we’re using:
Next, we need to tell RESTKit to use the Core Data model we have so meticulously created . The method [NSManagedObjectModel mergedModelFromBundles:nil] will return all the models from the main bundle merged into a single model. Since we have only one model in our bundle, we will get exactly it. Now we can create an object of RKManagedObjectStore type. We will initialize it with our managedObjectModel. Lastly, we need to assign this resulting object to the managedObjectStore property of RESTKit’s objectManager.
The next step is to complete Core Data stack initialization. The following piece of code initializes a persistent store coordinator, creates managed object contexts and configures managed object cache.
In result, our application:didFinishLaunchingWithOptions: method should resemble the following:
RESTKit entity mapping
Now that we have initialized RESTKit and Core Data stack it’s time to define mappings. To put it simply, we have to tell RESTKit how it should map API responses into local Core Data objects.
Let’s start by defining a mapping for the entity ArticleList, which we earlier defined in the Core Data model. We start by creating an object of RKEntityMapping class, which we will now use to define this mapping. Next, we need to specify a unique identification attribute, or a combination of attributes, in order to identify instances of our Core Data entity. The attribute title is a good candidate for ArticleList’s unique indentifier, as we can safely assume that all article lists provided by the Feedzilla API have unique titles.
Now comes the most important part. We need to define how the incoming JSON objects will be mapped into local Core Data objects. As a reminder here’s the structure of that JSON:
It contains three fields: title, syndication_url and description as well as a nested array articles. Let’s have a look now at the ArticleList.h file which is a model file for the Core Data entity ArticleList. It contains the following properties:
What we need to do now is to define mappings from the JSON object into properties of the ArticleList class. Let’s start with the three simple JSON fields: title, syndication_url and description, which we are now going to map into the following properties of ArticleList class: title, url and article_description. We will do it by invoking addAttributeMappingsFromDictionary: method on the articleListMapping object that we just created. This method takes an NSDictionary object as the only parameter.
Looking at the above, mapping attributes seems pretty straightforward. Dictionary keys refer to field names in the incoming object, while the corresponding values refer to the properties in the local model file.
What’s left now is to define a mapping for the nested articles array. Before we do that, we need to define mappings for the Article Core Data entity. If we compare the Article class generated from our Core Data model:
with the JSON object that we get from the API, we’ll see that field names in the JSON match exactly the names of properties in the Article class. In such case, instead of using an NSDictionary, we may use a simple NSArray:
Finally, here’s how we define a mapping for the nested articles array:
What we do here is we add a relationship mapping to the articleListMapping object we already declared. This new mapping is from the nested array articles in the incoming JSON object to the property articles in the Core Data entity ArticleList. Moreover, we declare that the nested array contains objects that should be mapped using articleMapping, that is into instances of Core Data entity Article.
Last, but not least, we have to register our articleListMapping so that it is used with the API endpoint that returns in response a list of articles in the chosen category. We do so by initializing an object of RKResponseDescriptor class and adding it to RESTKit’s objectManager. When declaring a response descriptor we define a mapping and a path pattern. From now on, all API responses from endpoints defined by the specified path pattern will mapped using the specified mapping.
Remember how we defined the objectManager using a base url? That base url was http://api.feedzilla.com. After the response descriptor was added to the objectManager all responses from the API at path: http://api.feedzilla.com/v1/categories/:id/articles.json will be mapped using articleListMapping. The colon in :id denotes id as a parameter. So for instance both responses from http://api.feedzilla.com/v1/categories/16/articles.json and from http://api.feedzilla.com/v1/categories/8/articles.json will be mapped using articleListMapping.
We can also enable the activity indicator in the application’s top bar, which will be helpful in case the API takes some time to return data.
Below is the full code that we have written so far to configure mappings. Again, we can place it in application:didFinishLaunchingWithOptions: method just above return YES; statement.
First API request
Now that we have configured RESTKit it’s time to make our very first request and see the response mapped into a Core Data object. In MasterViewController.m file let’s add a property to hold the incoming list of articles in an NSArray:
Now let’s add the two following methods at the end of the file:
In method requestData a RESTKit request to the provided API endpoint is made. If the request is successful, the success block of code is invoked by which time the incoming data has been safely saved to Core Data. In that block of code the other method, fetchArticlesFromContext is invoked. What follows is a standard Core Data fetch request on the main queue managed context provided by RESTKit’s default object store. In result an array of articles is assigned to the self.articles property. Please note that articleList.articles is an NSSet object therefore the method allObjects is invoked on it to obtain an NSArray of objects.
The very last step is to configure the table view. It’s pretty straightforward, we will display articles’ titles in consecutive cells, while pressing on a cell will take us to the detail view which in turn shall display a summary of the chosen article. Method requestData is invoked in viewDidLoad. Moreover, unnecessary code used to handle cell editing was also removed. Here’s the complete MasterViewController.
In effect we have a functioning master-detail application. Since all the data fetched from the API is stored in CoreData, it is available offline.
In this tutorial we learned how to use RESTKit framework to fetch data from remote APIs and store it in Core Data. We created a Core Data model for a nested array of objects and properly configured an object mapping for it.
The main advantage of using RESTKit is that once models for local objects are created and mappings are set up, interaction with RESTful services is simple and fast. That’s because handling network connections, parsing JSONs and mapping objects is all taken care of!
The final project is available at https://github.com/bonzoq/RESTKitTutorial .
Thanks to Paweł Kowalczyk for reading drafts of this.
Marcin Kmiec is an iOS developer and consultant. You can reach him through his website.