This site has been archived and you can no longer log in or post new messages. For up-to-date community resources please visit ezplatform.com

eZ Community » Learn » eZ Publish » Building native mobile applications...

Building native mobile applications with the eZ Publish REST API

Thursday 13 October 2011 4:21:48 pm

  • Currently 4 out of 5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

iOS application, continued

Next, add the following line to “JSONTableViewController.h”:

#import "JSON.h"
 

We have successfully added the JSON framework into our “Reader” project. Now we can use it to read the data returned by the eZ Publish REST web service.

Earlier, we created “JSONTableViewController”, which will be responsible for fetching the node list, storing the nodes, and presenting each node’s name in the table view. In “JSONTableViewController.h”, add an instance variable for the storage array:

@interface JSONTableViewController : UITableViewController {
    NSMutableArray *nodes;
}
@end
 

Next, in “JSONTableViewController.m”, override the designated initializer “initWithStyle:” to instantiate the nodes.

- (id)initWithStyle:(UITableViewStyle)style
{
    self = [super initWithStyle:style];
    if (self) {
        nodes = [[NSMutableArray alloc] init];
        
        self.title = @"Reader";
    }
    return self;
}
 

Notice that we have also set the title for this controller to “Reader”.

Since we are going to operate on nodes, we need to create a business object that will hold node-related information. Select the “Reader” group from the left pane, then select “New File...” from the “File” menu. Choose “Objective-C class”, then click the “Next” button. Make sure that the newly created class is a subclass of “NSObject”, then click the “Next” button. Give it the name “Node”. This class will be a definition for our node business objects.

Add the following line to “JSONTableViewController.h”:

#import "Node.h"
 

Next we need to implement the data source methods to return cells displaying text strings:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    // Return the number of sections.
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // Return the number of rows in the section.
    return [nodes count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }
    
    Node *node = [nodes objectAtIndex:[indexPath row]];
    
    [[cell textLabel] setText:node.name];
    
    return cell;
}
 

Build and run the application. You should see an empty table view on the screen.

Now we are going to fetch some data from the eZ Publish REST web service. To help with this, there are three classes: “NSURL”, “NSURLRequest” and “NSURLConnection”. Each of these classes has an important role in communicating with a web server.

Open “JSONTableViewController.h” and add two instance variables and a method declaration:

@interface JSONTableViewController : UITableViewController {
    NSMutableArray *nodes;
    NSMutableData *jsonData;
    NSURLConnection *connectionInProgress;
}

- (void)loadData;

@end
 

“NSURLConnection” instances can communicate with a web server in two ways: synchronously and asynchronously. We will perform an asynchronous connection.

In “JSONTableViewController.m”, we need to implement the “loadData” method to create an “NSURLRequest” within which we will make a connection to the eZ Publish REST web service. “NSURLRequest” will poll http://www.example.com/api/ezp/content/node/2/list for information about the child nodes of node 2 in JSON format, using “NSURLConnection” to make the connection.

- (void)loadData
{
    [nodes removeAllObjects];
    [[self tableView] reloadData];
    
    NSURL *url = [NSURL URLWithString:@"http://www.example.com/api/ezp/content/node/2/list"];
    
    NSURLRequest *request = [NSURLRequest requestWithURL:url 
                                             cachePolicy:NSURLRequestReloadIgnoringCacheData 
                                         timeoutInterval:30];
    if (connectionInProgress)
    {
        [connectionInProgress cancel];
        [connectionInProgress release];
    }
    
    [jsonData release];
    jsonData = [[NSMutableData alloc] init];
    
    connectionInProgress = [[NSURLConnection alloc] initWithRequest:request 
                                                           delegate:self 
                                                   startImmediately:YES];
}
 

We want the connection to be made whenever the “JSONTableViewController” table view appears on the screen; to do this, we will override “viewWillAppear” in “JSONTableViewController.m”

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self loadData];
}
 

Build the application to make sure there are no syntax errors. We shouldn’t see any data on the screen yet, as we need to implement some of the delegate methods for “NSURLConnection” to actually use the JSON data returned from the request.

Implement the following method in “JSONTableViewController.m” to put all of the data received by the connection into the instance variable “jsonData”.

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [jsonData appendData:data];
}
 

When a connection has finished retrieving all of the data from a web service, it sends the message “connectionDidFinishLoading:” to its delegate. Implement this method in “JSONTableViewController.m” in order to translate JSON data into node business objects.

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSString *jsonString = [[[NSString alloc] initWithData:jsonData 
                                                  encoding:NSUTF8StringEncoding] autorelease];
    
    for (NSDictionary *childNode in [[jsonString JSONValue] objectForKey:@"childrenNodes"])
    {
        Node *node = [[Node alloc] init];
        node.id = [[childNode objectForKey:@"nodeId"] intValue];
        node.name = [childNode objectForKey:@"objectName"];
        
        [nodes addObject:node];
        [node release];
    }
    
    [[self tableView] reloadData];
}
 

Build and run the application. The table should now display the node names received from the web service.

Now let’s implement a view to display actual node content. First, we need to create a new “DetailViewController”. Select “New” -> “New File...” from the “File” menu. Next, choose “UIViewController subclass” and click the “Next” button. On the next screen, verify that the “Subclass of” field contains the “UIViewController” class, and that the “With XIB for user interface” checkbox is marked. Then, click the “Next” button and name the view “DetailViewController.m”.

Our detail view requires some additional information passed from the table list view. We will implement the custom object initializer “initWithNode:” and pass a Node object as an argument.

Add the following node instance variable and custom object initalizer method to “DetailViewController.h”:

#import "Node.h"

@interface DetailViewController : UIViewController {
    Node *node;
}

@property (nonatomic, retain) Node *node;

- (id)initWithNode:(Node *)object;

@end
 

Next, add the object initializer implementation by replacing the “initWithNibName:bundle:” method with the following in “DetailViewController.m”. Notice the “self.title” parameter, which will correspond to the title of the browsing window.

- (id)initWithNode:(Node *)object
{
    self = [self initWithNibName:@"DetailViewController" bundle:nil];
    if (self) {
        self.node = object;
        self.title = object.name;
    }
    return self;
}

- (void)dealloc
{
    [node release];

    [super dealloc];
}
 

Then, add the following code to “JSONTableViewController.h”:

#import "DetailViewController.h"
 

Next, we need to handle the action when a table view row is selected. This action is handled by the table view delegate method “tableView:didSelectRowAtIndexPath:”:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    Node *node = [nodes objectAtIndex:[indexPath row]];

    DetailViewController *detailViewController = [[DetailViewController alloc] initWithNode:node];

    [self.navigationController pushViewController:detailViewController animated:YES];
    [detailViewController release];
}
 

Build and run application. When you tap on a table row, the detail view should appear. Since navigation is handled by “UINavigationController”, you can tap the “Reader” button to go back to the table list view. Recall that “Reader” comes from the value of “self.title” defined a bit earlier in the “DetailViewController.m” object initializer implementation.

Reader - iOS - landung page

Reader - iOS - getting started

 

Notice how the title bar for the detail view changes according to the selected node item from the table list view.

 

Populating the detail view

The next step is to implement the communication functions to get the actual content for a selected node. We will re-use the same concept and code for an asynchronous connection to the eZ Publish REST web service.

Open DetailViewController.h and add three instance variables and a method declaration:

@interface DetailViewController : UIViewController {
    Node *node;
    IBOutlet UIWebView *webView;
    NSMutableData *jsonData;
    NSURLConnection *connectionInProgress;
}

@property (nonatomic, retain) Node *node;

- (id)initWithNode:(Node *)object;
- (void)loadData;

@end
 

“IBOutlet” in front of the instance variable should clue you into the fact that we are going to use the Interface Builder to lay out the interface for the “DetailViewController” view. When we created “DetailViewController”, an XIB file of the same name was created and added to the project. Open “DetailViewController.xib” now.

In the right pane, find the “UIWebView” control in the object library and drag it into the view.

right-pane UI Web View

 

Next, make a connection from the file’s owner to that object, as shown below:

DetailViewController

 

In “DetailViewController.m”, we need to implement the “loadData” method to create an “NSURLRequest” to connect using the eZ Publish REST API. “NSURLRequest” will poll http://www.example.com/api/ezp/content/node/NODE_ID?OutputFormat=xhtml for information about the node NODE_ID in JSON format. The “NSURLConnection” instance makes the connection. (Note that the “xhtml” value for the “OutputFormat” GET parameter corresponds to the format of the value of the “renderedOutput” element, not the format of the returned data as a whole; see this page for more information.)

- (void)loadData
{    
    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://www.example.com/api/ezp/content/node/%i?OutputFormat=xhtml", node.id]];
    
    NSURLRequest *request = [NSURLRequest requestWithURL:url 
                                             cachePolicy:NSURLRequestReloadIgnoringCacheData 
                                         timeoutInterval:30];
    if (connectionInProgress)
    {
        [connectionInProgress cancel];
        [connectionInProgress release];
    }
    
    [jsonData release];
    jsonData = [[NSMutableData alloc] init];
    
    connectionInProgress = [[NSURLConnection alloc] initWithRequest:request 
                                                           delegate:self 
                                                   startImmediately:YES];
}
 

Override “viewWillAppear:” in “DetailViewController.m” to load the data whenever the “DetailViewController” view appears:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self loadData];
}
 

Implement the following method in “DetailViewController.m” to put all of the data received by the connection into the instance variable “jsonData”:

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [jsonData appendData:data];
}
 

As before for the table list view, implement the “connectionDidFinishLoading:” method in “DetailViewController.m”. In this case, we will get the XHTML output for the requested node and pass it to the web view for rendering.

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSString *jsonString = [[[NSString alloc] initWithData:jsonData 
                                                  encoding:NSUTF8StringEncoding] autorelease];

    [webView loadHTMLString:[[jsonString JSONValue] objectForKey:@"renderedOutput"] baseURL:nil];
}
 

When the “DetailViewController” view gets unloaded, its subviews will still be retained by “DetailViewController”. They need to be released and set to “nil” in “viewDidUnload” by overriding this method in “DetailViewController.m”:

- (void)viewDidUnload {
   [super viewDidUnload];

   [webView release];
   webView = nil;
}
 

Finally, we need to update the “dealloc” method, which frees up the object’s memory and disposes of any resources it holds, including ownership of any object instance variables:

- (void)dealloc {
   [node release]
   [webView release];
   [jsonData release];
   [connectionInProgress release];

   [super dealloc];
}
 

That’s all! Build and run the application to verify that everything works.

 
36 542 Users on board!

Tutorial menu

Printable

Printer Friendly version of the full article on one page with plain styles

Author(s)

Proudly Developed with from