Start tracking your progress
Trailhead Home
Trailhead Home

Understand Forceios Native Apps

Learning Objectives

After completing this unit, you'll be able to:

  • Understand the overall flow of a native iOS Salesforce app.
  • Understand the flow of events during app launch.
  • Understand how the root view controller directs the flow of execution.

Overview of Application Flow

Let’s take a closer look at native iOS apps.

On the surface, a Mobile SDK native app is just a typical iOS app. You can picture its architecture in Model-View-Controller (MVC) terms:

  • Model is the Lightning Platform database schema.
  • Views come from the nib and implementation files in your project.
  • Controller functionality comes in the form of iOS Cocoa Touch classes, Salesforce Mobile SDK controller classes, and custom controller classes in your app.

Like all iOS apps, Mobile SDK native apps start with a boilerplate main module that sets up the main event loop. Xcode generates this file, and most humans never have reason to touch it. Mobile SDK template apps for iOS 12.4 also define three classes that you can customize.

Handles Mobile SDK initialization and user authentication. If authentication succeeds, it passes control to RootViewController.
Container for the Salesforce login screen
Entry point for your app

AppDelegate defers to a shared SDK manager object to coordinate Salesforce passcode and authentication tasks. The following diagram illustrates the startup flow for a native app using the most basic SDK manager, SalesforceManager.

Application flow diagram

By default, forceios native apps use MobileSyncSDKManager as the SDK manager class. This class enables the full range of Mobile SDK features.

Application Launch Flow

When a customer opens your app, a fairly complex sequence of events occurs. These events can include:

  • Applying your app’s configuration
  • Validating an app passcode (optional)
  • Performing Salesforce login and authentication
  • Launching Salesforce Mobile SDK and your app
A healthy dose of “wiggle room”—for instance, the ability to defer Salesforce login until after startup—can make handling these events a tricky proposition. Luckily, Mobile SDK keeps you from getting tangled up by providing the SDK manager object. This object enforces the proper bootstrap sequence so that you don’t have to worry about most startup events.

How you initialize Mobile SDK depends on your development language. Native Mobile SDK apps use , a specialized subclass of the SalesforceManager Swift class.

Most of the code that uses the SDK manager exists in a new forceios app. Let’s examine this code.

  1. In Xcode, open the AppDelegate.swift file.
  2. Scroll to the init method.

Here, you can see the app initializing Mobile SDK. For example, in a Swift app you call initializeSDK() on the MobileSyncSDKManager object. Internally, the app sets up handlers for launch events, such as user authentication, PIN code failures, and other error states. Except in extreme cases, you’re never directly involved in these events.

After Mobile SDK is initialized, the init method calls an authentication helper class to define what happens when the current user logs out. Essentially, the helper class resets the view and restarts the app.

The rest of the AppDelegate class implements UIApplicationDelegate protocol methods that you can customize as needed. Each of these methods contains commented instructions that tell you exactly what to do for the intended use case. For example, you can:

Customize the navigation bar
Follow the commented instructions in the application(_:didFinishLaunchingWithOptions:) method.
Register your app for push notifications
Follow the commented instructions in the application(_:didFinishLaunchingWithOptions:) method.
Register the customer’s device for push notifications
If you registered for push notifications, the application(_:didRegisterForRemoteNotificationsWithDeviceToken:) callback method passes you a device token. To register this device token with Mobile SDK and the Salesforce push notification manager, follow the commented instructions
Break the news if push notification registration fails
Sometimes, the app’s attempts to register for push notifications failed. You receive an error message in the application(_:didFailToRegisterForRemoteNotificationsWithError:) method, which you can handle as you wish.
Enable an IDP service
Planning to use this app as an identity provider services for your other Mobile SDK apps? You can enable the IDP service by following the commented instructions in the application(openURL:options:) method. To fully implement this feature, configure your apps as described in the Mobile SDK Development Guide.

The AppDelegate and RootViewController Classes

The AppDelegate class is, in a sense, the Mobile SDK control center of the app—or at least its launch pad. It handles app initialization and login, and then passes execution control to a root view. Let’s look at the source code to see how the app displays its views.

  1. In Xcode, open the AppDelegate.swift file.
  2. Search for “initializeAppViewState”.
    See the instance method implementation? Look at the next to last line of the method:
    self.window!.rootViewController = InitialViewController(nibName: nil, bundle: nil)

    This code sets the self.window.rootViewController property to a newly created InitialViewController object. The InitialViewController class is defined in your app, and it’s rather sparse and boring. This view, which is the first to appear, serves as a container for the Salesforce login screens. That’s all you need to know about it.

  3. Search for “setupRootViewController”.
    If you visit all the hits, you see that:
    • It’s called in the init method of AppDelegate.
    • It’s implemented as follows:
      func setupRootViewController()
          let rootVC = RootViewController(nibName: nil, bundle: nil)
          let navVC = UINavigationController(rootViewController: rootVC)
          self.window?.rootViewController = navVC

In the setupRootViewController instance method, AppDelegate creates a RootViewController instance as the app’s real first view. RootViewController is a custom class defined by this Mobile SDK template. Notice how convenient the name “RootViewController” is? It sounds a lot like the rootViewController property of the app’s window. Coincidence? Not likely, but that naming is just a convenience—not a requirement. In fact, if you don’t like that class name, you can use Xcode’s refactoring tool to rename it in this app.

Your root view controller is the starting place for your app’s UI. Before it's assigned to the rootViewController property, though, it's wrapped in a UINavigationController object. This wrapper manages a stack of views and lets you navigate between them. Because UINavigationController has been initialized with RootViewController, RootViewController always remains at the bottom of the UI stack. You can easily add other views on top of RootViewcontroller with the UINavigationController pushViewController(_:animated:) method.

What else does the RootViewController class do? It configures a table view—standard stuff for a class that inherits UITableViewController. RootViewController also uses the SalesforceRestAPI shared instance to handle Salesforce REST API requests and responses. First, let’s examine the UITableViewController behavior.

The UITableViewController Class

After the RootViewController class becomes your root view controller, it displays the main screen for your app. Let’s look at how this class customizes the app’s main view.

RootViewController inherits the UITableViewController class, which means it automatically displays a table of data. RootViewController performs some minor customization of UI details, and at runtime it loads Salesforce data into its tableView property. Under the hood, though, UITableViewController presents the customized view.

To see how RootViewController customizes the table presentation:
  1. In Xcode, open RootViewController.swift.
  2. Scroll to the following overridden UITableViewController method:
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
The most interesting snippet from this method’s code is this two-line sequence:
// Configure the cell to show the data.
let obj = dataRows[indexPath.row]
cell.textLabel?.text = obj["Name"] as? String
This code displays a name from a dictionary in a table cell. The dictionary (obj) has been extracted from the dataRows array. You’re probably wondering: What is this dataRows array, and when did it join this party? In the next unit, we learn that the RootViewController class also handles REST requests and responses. For example, it sets dataRows to contain Salesforce records obtained from a REST response. Thus, this example code sets the cell’s text label to a Name value from a Salesforce record. To establish one-to-one correspondence, the code uses the current cell’s row number—indexPath.row—as the index into the array.