---
title: DaVinci client deep dive for iOS
description: Applies to:
component: sdks
version: latest
page_id: sdks:davinci:tutorials/deep-dive-ios
canonical_url: https://docs.pingidentity.com/sdks/latest/davinci/tutorials/deep-dive-ios.html
revdate: Mon, 18 Nov 2024 12:13:37 +0100
keywords: ["DaVinci", "Flows", "Setup &amp; Configuration", "Source Code", "Integration"]
section_ids:
  installing_and_importing_the_davinci_client: Installing and importing the DaVinci client
  add_dependencies_using_spm_swift_package_manager: Add dependencies using SPM (Swift Package Manager)
  add_dependencies_using_cocoapods: Add dependencies using CocoaPods
  configuring_the_davinci_client: Configuring the DaVinci client
  stepping_through_davinci_flows: Stepping through DaVinci flows
  starting_a_davinci_flow: Starting a DaVinci flow
  determining_davinci_flow_node_type: Determining DaVinci flow node type
  continue_node_type_ios: Handling DaVinci flow collectors in continue nodes
  continuing_a_davinci_flow: Continuing a DaVinci flow
  error_node_type_ios: Handling DaVinci flow error nodes
  failure_node_type_ios: Handling DaVinci flow failure nodes
  success_node_type_ios: Handling DaVinci flow success nodes
  leverage_swiftui: Leverage SwiftUI
---

# DaVinci client deep dive for iOS

***Applies to***:

* [icon: square-o, set=fa]DaVinci client for Android

* [icon: check-square-o, set=fa]DaVinci client for iOS

* [icon: square-o, set=fa]DaVinci client for JavaScript

Configure DaVinci client module for iOS properties to connect to PingOne and step through an associated DaVinci flow.

## Installing and importing the DaVinci client

To use the DaVinci client for iOS, use Swift Package Manager (SPM) or Cocoapods to add the dependencies to your project.

### Add dependencies using SPM (Swift Package Manager)

You can install this by using SPM (Swift Package Manager) on the generated iOS project.

1. In Xcode,in the Project Navigator, right-click your project, and then click Add Package Dependencies…​.

2. In the **Search or Enter Package URL** field, enter the URL of the repo containing the DaVinci Client for iOS, `https://github.com/ForgeRock/ping-ios-sdk.git`.

3. In **Add to Project**, select the name of your project, and then click **Add Package**.

   Xcode shows a dialog containing the libraries available in the Ping (ForgeRock) SDK for iOS.

4. Select the `PingDavinci` library, and in the **Add to Target** column select the name of your project.

5. Repeat the previous step for any other Ping (ForgeRock) SDK libraries you want to add to your project.

6. Click **Add Package**.

   Xcode displays the chosen libraries and any prerequisites they might have in the **Package Dependencies** pane of the Project Navigator:

   ![Package dependencies in the Xcode package navigator pane.](../_images/Xcode-package-dependencies-dv-client.png)Figure 1. Package dependencies in the Xcode package navigator pane.

### Add dependencies using CocoaPods

1. If you do not already have CocoaPods, install the [latest version](https://guides.cocoapods.org/using/getting-started.html).

2. If you do not already have a Podfile, in a terminal window, run the following command to create a new [Podfile](https://guides.cocoapods.org/syntax/podfile.html):

   ```
   pod init
   ```

3. Add the following lines to your Podfile:

   ```
   pod 'PingDavinci'
   ```

4. Run the following command to install pods:

   ```
   pod install
   ```

## Configuring the DaVinci client

Configure DaVinci client for iOS properties to connect to PingOne and step through an associated DaVinci flow.

The following shows an example DaVinci client configuration, using the underlying `Oidc` module:

Configure DaVinci client connection properties

```swift
let daVinci = DaVinci.createDaVinci { config in
    // Oidc as module
    config.module(OidcModule.config) { oidcValue in
        oidcValue.clientId = "6c7eb89a-66e9-ab12-cd34-eeaf795650b2"
        oidcValue.discoveryEndpoint = "https://auth.pingone.com/3072206d-c6ce-ch15-m0nd-f87e972c7cc3/as/.well-known/openid-configuration"
        oidcValue.scopes = ["openid", "profile", "email", "address", "revoke"]
        oidcValue.redirectUri = "org.forgerock.demo://oauth2redirect"
        oidcValue.additionalParameters = ["customKey":"customValue"]
    }
}
```

For information on the properties available, refer to [Configure DaVinci client for iOS properties](../sdkconfiguration/configure-sdk-ios.html).

## Stepping through DaVinci flows

To authenticate your users the DaVinci client for iOS must start the flow, and step through each node.

|   |                                                                                                                              |
| - | ---------------------------------------------------------------------------------------------------------------------------- |
|   | For information on which connectors and fields the DaVinci client supports, refer to [Compatibility](../compatibility.html). |

### Starting a DaVinci flow

To start a DaVinci flow, call the `start()` method:

Start a DaVinci flow

```swift
var node = await daVinci.start()
```

### Determining DaVinci flow node type

Each step of the flow returns one of four node types:

* `ContinueNode`

  This type indicates there is input required from the client. The `node` object for this type contains a `collector` object, which describes the information it requires from the client.

  Learn more in [Handling DaVinci flow collectors in continue nodes](#continue_node_type_ios).

* `SuccessNode`

  This type indicates the flow is complete, and authentication was successful.

  Learn more in [Handling DaVinci flow success nodes](#success_node_type_ios).

* `ErrorNode`

  This type indicates an error in the data sent to the server. For example, an email address in an incorrect format, or a password that does not meet complexity requirements.

  You can correct the error and resubmit to continue the flow.

  Learn more in [Handling DaVinci flow error nodes](#error_node_type_ios).

* `FailureNode`

  This type indicates that the flow could not be completed and must be restarted. This can be caused by a server error, or a timeout.

  Learn more in [Handling DaVinci flow failure nodes](#failure_node_type_ios).

You can use the helper functions to determine which node type the server has returned:

Determine `node` type.

```swift
switch (node) {
  case is ContinueNode: do {}
  case is ErrorNode: do {}
  case is FailureNode: do {}
  case is SuccessNode: do {}
}
```

### Handling DaVinci flow collectors in continue nodes

The `ContinueNode` type contains `collectors`. These collectors define what information or action to request from the user, or client device.

|   |                                                                                                                                                          |
| - | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | For a list of supported collectors, refer to [Supported PingOne fields and collectors](../../release-notes/compatibility.html#supported-davinci-fields). |

There are specific collector types. For example there are `TextCollector` and `PasswordCollector` types.

To complete a DaVinci flow we recommend that you implement a component for each connector type you will encounter in the flow. Then you can iterate through the flow and handle each collector as you encounter it.

Access collectors in a `ContinueNode`

```swift
node.collectors.forEach { item in
    switch(item) {
    case is TextCollector:
        (item as! TextCollector).value = "My First Name"
    case is PasswordCollector:
        (item as! PasswordCollector).value = "My Password"
    case is SubmitCollector:
        (item as! SubmitCollector).value = "click me"
    case is FlowCollector:
        (item as! FlowCollector).value = "Forgot Password"
    }
}
```

### Continuing a DaVinci flow

After collecting the data for a node you can proceed to the next node in the flow by calling the `next()` method on your current `node` object.

Continue a DaVinci flow using `next()`

```swift
let next = node.next()
```

|   |                                                                                                                                                                  |
| - | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | You do not need to pass any parameters into the `next` method as the DaVinci client internally stores the updated object, ready to return to the PingOne server. |

The server responds with a new `node` object, just like when starting a flow initially.

Loop again through conditional checks on the new node's type to render the appropriate UI or take the appropriate action.

### Handling DaVinci flow error nodes

DaVinci flows return the `ErrorNode` type when it receives data that is incorrect, but you can fix the data and resubmit. For example, an email value submitted in an invalid format or a new password that is too short.

You can retrieve the error message by using `node.message()`, and the raw JSON response with `node.input`.

Displaying the reason for an error

```swift
let node = await daVinci.start() //Start the flow

//Determine the Node Type
switch (node) {
  case is ContinueNode: do {}
  case is FailureNode: do {}
  case is ErrorNode:
      (node as! ErrorNode).message //Retrieve the error message
  case is SuccessNode: do {}
}
```

|   |                                                                                                          |
| - | -------------------------------------------------------------------------------------------------------- |
|   | This is different than a `FailureNode` type, which you cannot resubmit and must restart the entire flow. |

You can retain a reference to the `node` you submit in case the next `node` you receive is an `ErrorNode` type. If so, you can re-render the previous form, and inject the error information from the new `ErrorNode` node.

After the user revises the data call `next()` as you did before.

### Handling DaVinci flow failure nodes

DaVinci flows return the `FailureNode` type if there has been an issue that prevents the flow from continuing. For example, the flow times out or suffers a server error.

You can retrieve the cause of the failure by using `node.cause()`, which is an `Error` instance.

Handling receipt of a `FailureNode` type

```swift
let node = await daVinci.start() //Start the flow

//Determine the Node Type
switch (node) {
  case is ContinueNode: do {}
  case is FailureNode:
    (node as! FailureNode).cause //Retrieve the cause of the Failure
  case is ErrorNode: do {}
  case is SuccessNode: do {}
}
```

You should offer to restart the flow on receipt of a `FailureNode` type.

### Handling DaVinci flow success nodes

DaVinci flows return the `SuccessNode` type when the user completes the flow and PingOne issues them a session.

To retrieve the existing session, you can use the following code:

Handling receipt of a `SuccessNode` type

```swift
let user: User? = await daVinci.user()

_ = await user?.token()
await user?.revoke()
_ = await user?.userinfo(cache: false)
await user?.logout()
```

## Leverage SwiftUI

The following shows how you could use the DaVinci client with SwiftUI:

ViewModel

```swift
//Define State that listen by the View

@Published var state: Node = EmptyNode()

//Start the DaVinci flow
let next = await daVinci.start()

//Update the state
state = next

func next(node: ContinueNode) {
   val next = await node.next()
   state = next

}
```

View

```swift
if let node = state.node {
    switch node {
    case is ContinueNode:
        // Handle ContinueNode case
        break
    case is ErrorNode:
        // Handle Error case
        break
    case is FailureNode:
        // Handle Failure case
        break
    case is SuccessNode:
        // Handle Success case
        break
    default:
        break
    }
}
```
