Getting Started with the Mobile SDK for iOS

Abstract

The Mobile SDK for iOS contains native Objective-C libraries, and an Xcode template to enable developers to rapidly build iOS applications that securely connect to Force.com and Database.com. This article describes how to get started using the SDK via code samples for the most common scenarios including Authentication, CRUD (Create Read Update Delete) operations, and handling errors.

Introduction

The Mobile SDK for the iOS is composed of two primary parts: firstly, the SDK includes a series of Objective-C libraries. These libraries support the Force.com and Database.com OAuth implementation, and provide wrappers for working with the Force.com and Database.com REST APIs. Secondly, the SDK provides a container based on PhoneGap. The container enables HTML5-based applications to leverage the libraries mentioned above for key enterprise requirements such as authentication and secure offline storage, effectively providing an enterprise-ready hybrid application container. This article shall focus on the former, the Mobile SDK libraries, and applies to developers already familiar with developing in Objective-C. If you are new to iOS development, I suggest you check out the the Apple Developer site for some great tutorials to get you started.

You should consider the terms Force.com and Database.com as interchangeable throughout this article. Database.com is the underlying database of the Force.com platform, with the REST API being available in both products. With the availability of the REST API, mobile developers no longer require specific vendor libraries for different devices and platforms to connect to their applications. REST provides a common architectural pattern for developers to connect to any system. The goal of the Mobile SDK is to wrap the Force.com REST API and OAuth implementation into a series of easy to use libraries that let developers focus on building their own applications for the iPhone and iPad without the need to learn a new platform or process.

Quick Start

Getting started with the Mobile SDK is easy. Depending on your requirements, you have two options: using the SDK in an existing project, or using the Xcode templates. Both approaches require you to download and install the SDK. It should go without saying that, in order to develop iOS apps, you need to be running Mac OSX, and have Xcode already installed. This article was written using OSX 10.6.8 and Xcode 4.2 beta. Xcode 4.x is a required dependency.

To install the SDK follow these steps:

1. Using Git, you can clone the Open Source project on Github to your local machine via Terminal:

$ git clone https://github.com/forcedotcom/SalesforceMobileSDK-iOS.git

2. Run the installer script to fetch required dependencies, and install the template projects into Xcode

$ cd SalesforceMobileSDK-iOS
$ ./install.sh

Using the SDK in an Existing Project

If you have an existing project, make sure to follow the instructions above to install the SDK libraries. Next, you can perform the following steps to get up and running:

  • Drag the folder native/dependencies into your project (check Create groups for any added folders)
  • Open the Build Settings tab for the project.
  • Set Other Linker Flags to -all_load
  • Open the Build Phases tab for the project main target and link against the following required frameworks:
    • CFNetwork.framework
    • CoreData.framework
    • MobileCoreServices.framework
    • SystemConfiguration.framework
    • Security.framework
    • libxml2.dylib

From there, all you need to do is add the relevant headers into your .m. For example, to use the REST API, you must include the following line:

#import "SFRestAPI.h";

The steps above configure your project to use the Mobile SDK. You will still need to include the relevant hooks for authentication and response handling from Force.com. We will cover these in Working with the SDK later in this article.

Using the Xcode Project Template

The easiest, and most expeditious way to get started with the Mobile SDK is to use the Xcode Native Force.com REST App project template. This template (see the screenshot below) generates a simple application with views and controllers for handling authentication to Force.com. Using the template is what we recommend for you to get started quickly.

For the majority of examples in this article, we are going to use the default project that the Native Force.com REST App project template generates. Let's start by creating a new project. If you are following along with Xcode open, go ahead and double click on the Native Force.com REST App. Xcode then presents you with a wizard asking for the following information.

Name Description
Product Name Unique name of your application
Company Identifier Unique identifier, typically in the form of the name of your url, eg: salesforce for www.salesforce.com
Consumer Key Used for OAuth2 authentication. This must match the Consumer Key in the Remote Access settings of your Force.com app. See Authentication for more information and Configuring OAuth 2.0 Access for your Application for specific instructions. For testing, you can use the default values.
Redirect URL Used as part of the OAuth2 flow. This must match the Callback URL in the Remote Access settings of your Force.com app. See Authentication for more information and Configuring OAuth 2.0 Access for your Application for specific instructions. For testing, you can use the default values.
Use Automatic Reference Counting Currently not supported by the template. Make sure that you uncheck this field.

Once you specify values for the wizard, click Next, choose where to save your app, and click Create. At this point you have a working app which can securely connect to Force.com. Click Run, login with your org credentials, and try it out for yourself! If you need to change any of the values which you entered during the wizard process, you can update these at any time via the AppDelegate.m class.

In addition, the template project is configured to connect to a production, or developer instance of Force.com. If you want to use a sandbox environment, you can add the following line to AppDelegate.m

static NSString *const OAuthLoginDomain = @"test.salesforce.com";

Working with the SDK

The following section describes the most common scenarios you are likely to require when working with Force.com, including Authentication, CRUD Operations, and Handling Responses. Before you jump in, however, a quick note on design patterns.

iOS uses, and promotes, a number of design patterns for building great apps. The iOS libraries use one of these patterns extensively -- Delegate. The Delegate pattern effectively tells Objective-C which class can handle specific events considering the delegate a particular interface implements. The Mobile SDK frequently uses the Delegate pattern to encapsulate logic.

Looking at the SFNativeRestAppDelegate.h, for example, we can see that this interface implements the SFOAuthCoordinatorDelegate.h. This interface contains the important methods we should handle in our code for authentication: login, loggedIn, and logout. Thanks to the Delegate pattern, we know SFNativeRestAppDelegate.m, that implements SFOAuthCoordinatorDelegate, will be able to handle these methods. Let's look at the the implementation that the Xcode project template generates for us.

@interface SFNativeRestAppDelegate : NSObject <UIApplicationDelegate,
     SFOAuthCoordinatorDelegate, UIAlertViewDelegate> 


Authentication

Before your app can begin working with Force.com, you must authenticate. The preferred authentication method for mobile apps is OAuth 2. A complete discussion of OAuth is beyond the scope of this article. If you want more information on OAuth, the Digging Deeper in OAuth 2 article provides a great technical discussion on how OAuth works on the Force.com platform. Thankfully, the Mobile SDK does much of the heavy lifting for you and allows to you focus on just what you need. Let's look at some of the code that the template generates in SFNativeRestAppDelegate.m to get a better understanding on what's going on.

Login

- (void)login {
   //kickoff authentication
   [self.coordinator authenticate];
}

The login method calls the coordinator's (self, or the current class) authenticate method, passing in the credentials [#Using the Xcode Project Template | you specified in the wizard].

SFOAuthCredentials *creds = [[SFOAuthCredentials alloc] 
                                    initWithIdentifier:fullKeychainIdentifier  
                                    clientId: [self remoteAccessConsumerKey] ];

The generated project takes care of presenting a login screen and delegate callbacks upon successful (or unsuccessful) authentication requests via the SFOAuthCoordinatorDelegate methods. For example, when a login is successful, the following delegate method is called, which in turn calls the LoggedIn method. If you are using the Mobile SDK libraries in an existing project, you will need to implement the view required to display the Force.com username/password screen.

- (void)oauthCoordinatorDidAuthenticate:(SFOAuthCoordinator *)coordinator {
   NSLog(@"oauthCoordinatorDidAuthenticate for userId: %@", coordinator.credentials.userId);
   [coordinator.view removeFromSuperview];
   [self loggedIn];

}

Unsuccessful Login

If something went wrong with authentication, the SFOAuthCoordinatorDelegate will call the didFailWithError method. By default, the generated project displays the error in an alert-style dialog. If you wanted to handle errors differently, go ahead and modify this method.

- (void)oauthCoordinator:(SFOAuthCoordinator *)coordinator didFailWithError:(NSError *)error {
   NSLog(@"oauthCoordinator:didFailWithError: %@", error);
   [coordinator.view removeFromSuperview];
   
   if (error.code == kSFOAuthErrorInvalidGrant) {  //invalid cached refresh token
       //restart the login process asynchronously
       NSLog(@"Logging out because oauth failed with error code: %d",error.code);
       [self performSelector:@selector(logout) withObject:nil afterDelay:0];
   }
   else {
       // show alert and retry
       UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Salesforce Error" 
             message:[NSString stringWithFormat:@"Can't connect to salesforce: %@", error]
             delegate:self
              cancelButtonTitle:@"Retry"
              otherButtonTitles: nil];
       [alert show];
       [alert release];
   }
}

LoggedIn

Upon successful login, the LoggedIn method is called. This is where you can perform any post-login functions. One typical action is to hide the view used to display the login screen, and present the user with the first 'real' view from your application. The generated project displays the RootViewController with a TableView containing a list of users in your org.

- (void)loggedIn {
   //provide the Rest API with a reference to the coordinator we used for login
   [[SFRestAPI sharedInstance] setCoordinator:self.coordinator];
   
   // now show the true app view controller if it's not already shown
   if (nil != self.authViewController) {
       self.authViewController = nil;
   }
   
   if (nil == self.viewController) {
       UIViewController *rootVC = [self newRootViewController];
       self.viewController = rootVC;
       [rootVC release];
       self.window.rootViewController = self.viewController;
       [self.window makeKeyAndVisible];
   }
}

Logout

Just as important as logging into Force.com, a logout request should securely purge tokens, log you out of your Force.com session, and, perform any clean up functions you may require. SFOAuthCoordinatorDelegate's logout method is the place to handle these actions. Unless you do need to perform additional functions as part of the logout process, you should be able to leave the generated method alone. That's the nice thing about the Mobile SDK template project - you just need to focus on what you need to do, confident that the SDK is going to take care of the rest.

- (void)logout {
   [self.coordinator revokeAuthentication];
   [self.coordinator authenticate];
}

CRUD Operations

Awesome. You were able to securely log into Force.com. Now it is time to work with data. If you are like me, you work better with code samples. The Mobile SDK template project is intentionally simple - you want a starting point without requiring you to delete a bunch of code from the project that you don't need. The best place for CRUD operation samples is within the nifty RESTAPIExplorer app included in the SDK. Go ahead and navigate to SalesforceMobileSDK-iOS/native/SampleApps/RestAPIExplorer, and open the Xcode project, then navigate to RestAPIExplorerViewController.m to follow along.

You will notice in the following code snippets, the pattern is the same regardless of which operation you are performing: specify a Force.com object type (Standard or Custom object), set fields, prep a request for operation, and actually send the request. This is one of the great things about REST, and therefore the Mobile SDK wrappers - everything works on standard patterns.

Creating New Records

//any standard or custom object 
NSString *objectType = @"Contact";   //any standard or custom object
//NSDictionary of field names and values
NSDictionary *fields = [@"{FirstName:Quinton, LastName:Wall}" JSONValue];

//prep actual operation
SFRestRequest *request = [[SFRestAPI sharedInstance] requestForCreateWithObjectType:objectType fields:fields];

//send the request
[[SFRestAPI sharedInstance] send:request delegate:self];

You can also perform an upsert with the following operation:

request = [[SFRestAPI sharedInstance] requestForUpsertWithObjectType:objectType externalIdField:externalFieldId externalId:externalId fields:fields];

Querying for Data

Performing queries is pretty straight-forward. Write your query, and pass it to the requestForQuery method. Don't forget that the platform enforces governor limits any time you access Force.com. It is always good practice to add a Limit clause to any query.

//soql statement
NSString *query = @"Select Id, FirstName, LastName from Contact Limit 10";  

//prep actual operation
SFRestRequest *request = [[SFRestAPI sharedInstance] requestForQuery:query];

//send the request
[[SFRestAPI sharedInstance] send:request delegate:self];

Updating Data

Updating data requires you to specify the Force.com record Id, an object type, and an NSDictionary of name/value fields to update. If you are using custom objects, don't forget to include the __c in the object type definition, or field names.

//soql statement
NSString *objectId = @"1234567890";
NSString *objectType = @"Contact";  
NSDictionary *fields = [myFieldListStr JSONValue];

//prep actual operation
SFRestRequest *request = [[SFRestAPI sharedInstance] requestForUpdateWithObjectType:objectType objectId:objectId fields:fields];

//send the request
[[SFRestAPI sharedInstance] send:request delegate:self];

Deleting Records

Deleting records is very similar to an update, except you do not need to pass in an NSDictionary of field.

//soql statement
NSString *objectId = @"1234567890";
NSString *objectType = @"Contact";  
 
//prep actual operation
 SFRestRequest *request = [[SFRestAPI sharedInstance] requestForDeleteWithObjectType:objectType objectId:objectId];

//send the request
[[SFRestAPI sharedInstance] send:request delegate:self];

Handling Responses

In all of the examples above, notice the final line of code, which sends the request and utilizes the Delegate pattern again. In our example, we specify the delegate to be 'self'. In other words, the Delegate is the current class.

[[SFRestAPI sharedInstance] send:request delegate:self]; 

In order to handle Mobile SDK responses, your class must implement the SFRestDelegate. Looking at the RestAPIExplorerViewController.m, you can see we have this covered.

@interface RestAPIExplorerViewController : UIViewController <SFRestDelegate, UITextFieldDelegate> 

Successful Response

The didLoadResponse method handles a successful response from Force.com by returning a JSON String. We typically want to map these responses to a visual component such as a Table View.

- (void)request:(SFRestRequest *)request didLoadResponse:(id)jsonResponse {
  NSArray *records = [jsonResponse objectForKey:@"records"];
   NSLog(@"request:didLoadResponse: #records: %d", records.count);
   self.dataRows = records;
   [self.tableView reloadData];
   
}

Unsuccessful Response

Good developers always expect the unexpected. The didFailLoadWithError method handles errors in the request/response flow. Similar to handling login errors, we could present the error in a dialog, or perhaps we have a textfield in our UI for status updates

- (void)request:(SFRestRequest*)request didFailLoadWithError:(NSError*)error {
   tfStatus.backgroundColor = [UIColor redColor];
   tfStatus.text = [self formatRequest:request];
   tfStatus.text = [error description];
}

Canceling Requests

It is good practice to allow users to cancel requests, especially if the request may be long running. The requestDidCancelLoad method is the trick here.

- (void)requestDidCancelLoad:(SFRestRequest *)request {
   _tfResult.backgroundColor = [UIColor redColor];
   _tfResponseFor.text = [self formatRequest:request];
   _tfResult.text =  @"Request was cancelled";    
}

Request Time-Outs

Some times the Internet is an unpredictable thing, and requests can time out. You can leverage the requestDidTimeout method to handle such timeouts. A good practice may be to inform the user of the timeout, and potentially allow the user to retry the request:

- (void)requestDidTimeout:(SFRestRequest *)request {
   // show alert and retry
       UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Request timed out." 
              message:[NSString stringWithFormat:@"Looks like the Internet is  busy. : %@", error]
                   delegate:self
                   cancelButtonTitle:@"Retry"
                   otherButtonTitles: nil];
       [alert show];
       [alert release];
  
}

By now you should be comfortable with how delegates work. In the snippet above, we are setting the delegate (UIAlertViewDelegate) to self again to allow the current class to handle button clicks from alerts. We could kick off our request again within the delegate method:

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
   [self.doMyRequest ];
}

AppExchange Mobile

Congratulations! You’ve built your mobile app and now you are ready to get it into the hands of customers. But how? You’re only two steps away from getting your app to market. First, list your app on Apple App Store or Android Market. These are fantastic places to connect with millions of customers. Second, list on AppExchange Mobile. AppExchange Mobile is salesforce.com’s destination for mobile business apps and is part of the AppExchange – the leading business apps marketplace. As a Force.com mobile app developer, you have a unique opportunity to list on AppExchange Mobile, connecting you with a dedicated set of existing Salesforce customers who are waiting for great business apps like yours.

Learn more about listing on the AppExchange.

Learning More

So far, we have covered the major operations you will use on a regular basis when using the Mobile SDK, but we haven't touched all of them. The Mobile SDK also contains complete API-level docs in HTML format. These docs are a great resource for becoming more familiar with the SDK. To access these docs, navigate to SalesforceMobileSDK-iOS/native/SalesforceSDK/Documentation/html, and double-click index.html. If you are working with the SDK frequently, bookmarking this page will save you a lot of time.

Summary

The Mobile SDK for iOS makes it quicker than ever to write native applications that securely connect to Force.com and Database.com. Whether starting from scratch with the Xcode template, or importing libraries into an existing project, developers can now take advantage of the Cloud for native iPhone and iPad apps.

Throughout this article, we examined the most common scenarios you will need to handle when building Force.com and Database.com mobile apps. These scenarios include Authentication, CRUD (Create Read Update Delete) operations, and handling errors. As demonstrated within the code samples for each scenario, the Mobile SDK relies heavily on the Delegate pattern to 'register' event handlers. This Delegate pattern should be very familiar to you if you are an iOS developer, making it easy for you to learn, and leverage, the Mobile SDK APIs.

salesforce.com encourages developers and partners to take advantage of the Mobile Appexchange for listing the Force.com and Database.com mobile applications.


Finally, and perhaps most importantly, the Mobile SDK is a community driven, open source project hosted on Github. Whilst the SDK is maintained by salesforce.com engineering, we strongly encourage community contributions. After all, the Social Enterprise is a collaborative effort!

About the author

Quinton Wall is a Sr. Developer Evangelist at Salesforce.com , and aspiring fantasy author. He is a regular speaker at cloud and developer events around world, active contributor to open source projects, and the developer.force.com site. When he is not working with the Force.com platform, building mobile apps, or writing books, he can be found on twitter @quintonwall sharing his thoughts 140 characters at a time.