Develop a iOS Mobile App Consuming an OData
Service Running in SAP HANA Cloud Platform
TABLE OF CONTENTS
INTRODUCTION ... 3
1. DEVELOPING THE UI WITH STORYBOARD ... 4
2. WRITING THE CLASSES THAT REPRESENTS THE MODEL (ODATA SERVICE) ... 7
INTRODUCTION
In this document, we show how easy it is to create an iOS mobile app that consumes OData service running in SAP HANA Cloud Platform.
This document is for developers who knows iOS programming, but does not know how iOS apps can consume OData service running in SAP HANA Cloud Platform.
The OData service that we consume in the app is https://companylistdemo.hana.ondemand.com/refapp-companylist-web/companylist.svc/
We use “storyboard” here to develop the UI of the app. The app consists of 2 views.
The data for the views are from the OData service.
The detail page that shows up a list of employees for the selected company. The user can navigate back to the home page view
The data for the views are from the OData service.
Let’s get started on creating the app. We split this process into 3 steps. 1. Developing the UI with storyboard
2. Writing the classes that represents the model (OData service) 3. Consuming the OData service in the app and running the app
1. DEVELOPING THE UI WITH STORYBOARD
a. Open Xcode from the /Applications directory. The Xcode welcome window appears.
b. In the welcome window, click “Create a new Xcode project” (or choose File > New > Project). Xcode opens a new window and displays a dialog in which you can choose a template. Select “Empty Application” as shown and click on“Next” button.
c. In the dialog that appears, enter the following details: Product Name: CompanyList
Company identifier: com.sap.refapps
d. In the dialog that appears, choose a location for your project and click Create. Xcode opens your new project in a window (called the workspace window), which should look similar to this
e. Using the interface builder, create a storyboard called “Main.storyboard” which consists of the following scenes:
f. Create a “Objecttive-C class” called “CompanyViewController” that is a sub class of
“UITableViewController” in your project. This is for the company view (home page view). Add this as the class type for the home page view in the storyboard
g. Similarly, create “EmployeeViewController” class, which is for the employee view (detail page view). Add this as the class type for the detail page view in the storyboard
With this, we have completed the creation of the UI of the app using storyboard. Next we will create files for the model (OData service).
A table view controller embedded in navigation controller. This is the root view controller. This is for showing the list of companies
A table view controller for showing the list of employees, with a push segue from companies to employees
2. WRITING THE CLASSES THAT REPRESENTS THE MODEL (ODATA SERVICE)
a. Create a “Company” class that sub classes “NSObject”. The Company.h and Company.m files will be created. Similarly create an “Employee” class that sub classes “NSObject”. The Employee.h and Employee.m files will be created.
b. For the Company.h and Company.m, replace the existing code with the following
Company.h
#import <Foundation/Foundation.h>
@interface Company : NSObject
@property NSString *companyName;
@end
Company.m
#import "Company.h"
@implementation Company
@end
c. For the Employee.h and Employee.m, replace the existing code with the following
Employee.h
#import <Foundation/Foundation.h>
@interface Employee : NSObject
@property NSString *firstName;
@property NSString *lastName;
@end
Employee.m
#import "Employee.h"
@implementation Employee
3. CONSUMING THE ODATA SERVICE IN THE APP AND RUNNING THE APP
a. In the CompanyViewController.h, replace the existing code with the following
#import <UIKit/UIKit.h>
#import "Company.h"
@interface CompanyViewController : UITableViewController
@property Company *company;
@end
b. Next we will write the code for the CompanyViewController.m file. The complete source code for the file is given later, but now we explain the most important methods in this file.
- (void)loadInitialData method: This is the method where we call the OData service, parse the
JSON data response
For parsing the OData JSON response, we use open source JSON library https://github.com/stig/json-framework/
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender method: This method
is implemented to navigate to the employee view, when a company name is tapped. Also, the company name is passed to the employee view from here. By getting the company name in the detail view, we call the OData service using the filter option to request data of all employees who belong to the filtered company.
c. In the EmployeeViewController.h, replace the existing code with the following #import <UIKit/UIKit.h>
@interface EmployeeViewController : UITableViewController @property NSString *selectedCompany;
@end
d. Next we will write the code for the EmployeeViewController.m file. The complete source code for the file is given later, but now we explain the most important methods in this file.
CompanyViewController.m
//
// CompanyViewController.m
// CompanyList
//
// Copyright (c) 2013 com.sap.example. All rights reserved.
// #import "CompanyViewController.h" #import "Company.h" #import "EmployeeViewController.h" #import "SBJson.h" @interface CompanyViewController ()
@property NSMutableArray *companyList;
@end
@implementation CompanyViewController - (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) { // Custom initialization } return self; } - (void)loadInitialData {
SBJsonParser * parser = [[SBJsonParser alloc] init];
NSURL *mUrl = [NSURL URLWithString:@" https://companylistdemo.hana.ondemand.com/refapp-companylist-web/companylist.svc/Companys/?$format=json"];
NSURLRequest *request = [NSURLRequest requestWithURL:mUrl];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSDictionary *diclevel1 = [parser objectWithString:json_string];
NSDictionary *diclevel2 = [diclevel1 objectForKey:@"d"];
NSMutableArray *arraylevel1 = [diclevel2 objectForKey:@"results"];
NSLog(@"count: %lu", (unsigned long)[arraylevel1 count]);
for (NSDictionary *dictionaryItem in arraylevel1) {
NSString *compname = [dictionaryItem objectForKey:@"CompanyName"]; NSLog(@"Data: %@", compname);
Company *item1 = [[Company alloc] init];
item1.companyName = compname; [self.companyList addObject:item1]; } } - (void)viewDidLoad { [super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (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 [self.companyList count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"PrototypeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
Company *company = [self.companyList objectAtIndex:indexPath.row];
cell.textLabel.text = company.companyName;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
Company *selectedCompany = [self.companyList objectAtIndex:indexPath.row];
[self performSegueWithIdentifier:@"ToEmployeeView" sender:selectedCompany.companyName];
}
// This will get called too before the view appears
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:@"ToEmployeeView"]) { // Get destination view
EmployeeViewController *ec = [segue destinationViewController];
// Pass the information to your destination view
ec.selectedCompany = (NSString *) sender;
}
}
EmployeeViewController.m
//
// EmployeeViewController.m
// CompanyList
//
// Copyright (c) 2013 com.sap.example. All rights reserved.
//
#import "EmployeeViewController.h" #import "Employee.h"
#import "SBJson.h"
@interface EmployeeViewController ()
@property NSMutableArray *employeeList;
@end
@implementation EmployeeViewController
- (id)initWithStyle:(UITableViewStyle)style {
self = [super initWithStyle:style];
if (self) { // Custom initialization } return self; } - (void)loadInitialData {
NSMutableString *url = [[NSMutableString alloc]init];
[url appendString:@" https://companylistdemo.hana.ondemand.com/refapp-companylist-web/companylist.svc/Employees/?$format=json&$filter=CompanyId eq "];
[url appendString:@"'"];
[url appendString:self.selectedCompany];
[url appendString:@"'"];
NSLog(@"URL Constructed with spaces: %@", url);
NSString *newUrl = [url stringByReplacingOccurrencesOfString:@" " withString:@"%20"];
NSLog(@"URL Constructed with spaces replaced : %@", newUrl);
SBJsonParser * parser = [[SBJsonParser alloc] init];
NSURL *mUrl = [NSURL URLWithString:newUrl];
NSURLRequest *request = [NSURLRequest requestWithURL:mUrl];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSLog(@"Response Data: %@", json_string);
NSDictionary *diclevel1 = [parser objectWithString:json_string];
NSDictionary *diclevel2 = [diclevel1 objectForKey:@"d"];
NSMutableArray *arraylevel1 = [diclevel2 objectForKey:@"results"];
NSLog(@"count: %lu", (unsigned long)[arraylevel1 count]);
for (NSDictionary *dictionaryItem in arraylevel1) {
NSString *lastname = [dictionaryItem objectForKey:@"LastName"];
NSString *firstname = [dictionaryItem objectForKey:@"FirstName"];
NSLog(@"Data: %@", lastname);
NSLog(@"Data: %@", firstname);
Employee *item = [[Employee alloc] init]; item.firstName = firstname;
[self.employeeList addObject:item]; } } - (void)viewDidLoad { [super viewDidLoad];
self.employeeList = [[NSMutableArray alloc] init]; [self loadInitialData];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (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 [self.employeeList count];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"EmployeeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
Employee *employee = [self.employeeList objectAtIndex:indexPath.row];
cell.textLabel.text = employee.firstName; cell.detailTextLabel.text = employee.lastName; return cell; } @end
Build the project. Your app should not show any errors. Running the app will launch the app in the simulator.
© 2013 SAP AG. All rights reserved.
SAP, R/3, SAP NetWeaver, Duet, PartnerEdge, ByDesign, SAP BusinessObjects Explorer, StreamWork, SAP HANA, and other SAP products and services mentioned herein as well as their respective logos are trademarks or registered trademarks of SAP AG in Germany and other countries.
Business Objects and the Business Objects logo, BusinessObjects, Crystal Reports, Crystal Decisions, Web Intelligence, Xcelsius, and other Business Objects products and services mentioned herein as well as their respective logos are trademarks or registered trademarks of Business Objects Software Ltd. Business Objects is an SAP company.
Sybase and Adaptive Server, iAnywhere, Sybase 365, SQL Anywhere, and other Sybase products and services mentioned herein as well as their respective logos are trademarks or registered trademarks of Sybase Inc. Sybase is an SAP company. Crossgate, m@gic EDDY, B2B 360°, and B2B 360° Services are registered trademarks of Crossgate AG in Germany and other countries. Crossgate is an SAP company.
All other product and service names mentioned are the trademarks of their respective companies. Data contained in this document serves informational purposes only. National product specifications may vary. These materials are subject to change without notice. These materials are provided by SAP AG and its affiliated companies ("SAP Group") for informational purposes only, without representation or warranty of any kind, and SAP Group shall not be liable for errors or omissions with respect to the materials. The only warranties for SAP Group products and services are those that are set forth in the express warranty statements accompanying such products and services, if