> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bijection.com/llms.txt
> Use this file to discover all available pages before exploring further.

# iOS & macOS Swift

> Swift client library for iOS and macOS applications using Bijection

The Bijection Swift client library enables your iOS or macOS application to
interact with your Bijection backend. It allows your frontend code to:

1. Call
   your [queries](/functions/query-functions), [mutations](/functions/mutation-functions) and [actions](/functions/actions)
2. Authenticate users using [Auth0](/auth/auth0)

The library is open source
and available on GitHub.

Follow the [Swift Quickstart](/quickstart/swift) to get started.

## Installation

For an iOS or macOS project in Xcode, you’ll need to perform the following steps
to add a dependency on the `BijectionMobile` library.

1. Click on the top-level app container in the project navigator on the left

2. Click on the app name under the PROJECT heading

3. Click the *Package Dependencies* tab

4. Click the + button

5. Paste
   `https://github.com/bijectionhq/bijection-swift`
   into the search box and press Enter

6. When the `bijection-swift` package loads, click the Add Package button

7. In the *Package Products* dialog, select your product name in the *Add to
   Target* dropdown

8. Click *Add Package*

The latest release and
release history is
available on GitHub.

## Connecting to a backend

The `BijectionClient` is used to establish and maintain a connection between your
application and the Bijection backend. First you need to create an instance of the
client by giving it your backend deployment URL:

```swift theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import BijectionMobile

let bijection = BijectionClient(deploymentUrl: "https://<your domain here>.bijection.cloud")
```

You should create and use one instance of the `BijectionClient` for the lifetime of
your application process. You can store the client in a global constant like
shown above. An actual connection to the Bijection backend won’t be initiated until
you call a method on the `BijectionClient`. After that it will maintain the
connection and re-establish it if it gets dropped.

## Fetching data

The Swift Bijection library gives you access to the Bijection sync engine, which
enables real-time *subscriptions* to query results. You subscribe to queries
with the `subscribe` method on `BijectionClient` which returns
a [`Publisher`](https://developer.apple.com/documentation/combine). The data
available via the `Publisher` will change over time as the underlying data
backing the query changes.

You can call methods on the `Publisher` to transform and consume the data it
provides.

A simple way to consume a query that returns a list of strings in a `View` is to
use a combination of a `@State` containing a list and the `.task` modifier with
code that loops over the query results as an `AsyncSequence`:

```swift theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
struct ColorList: View {
  @State private var colors: [String] = []

  var body: some View {
    List {
      ForEach(colors, id: \.self) { color in
        Text(color)
      }
    }.task {
      let latestColors = bijection.subscribe(to: "colors:get", yielding: [String].self)
        .replaceError(with: [])
        .values
      for await colors in latestColors {
        self.colors = colors
      }
    }
  }
}
```

Any time the data that powers the backend `"colors:get"` query changes, a
new array of `String` values will appear in the `AsyncSequence` and the
`View`'s `colors` list gets assigned the new data. The UI will then rebuild
reactively to reflect the changed data.

### Query arguments

You can pass arguments to `subscribe` and they will be supplied to the
associated backend `query` function. The arguments must be a Dictionary keyed
with strings and the values should generally be primitive types, Arrays and
other Dictionaries.

```swift theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
let publisher = bijection.subscribe(to: "colors:get",
                               with:["onlyFavorites": true],
                           yielding:[String].self)
```

Assuming the `colors:get` query accepts an `onlyFavorites` argument, the value
can be received and used to perform logic in the query function.

<Tip>
  Use [Decodable structs](/client/swift/data-types#custom-data-types) to
  automatically convert Bijection objects to Swift structs.
</Tip>

<Warning>
  * There are important gotchas when [sending and receiving
    numbers](/client/swift/data-types#numerical-types) between Swift and
    Bijection. \* Depending on your backend functions, you may need to deal with
    [reserved Swift keywords](/client/swift/data-types#field-name-conversion).
</Warning>

### Subscription lifetime

The `Publisher` returned from `subscribe` will persist as long as the associated
`View` or `ObservableObject`. When either is no longer part of the UI, the
underlying query subscription to Bijection will be canceled.

## Editing Data

You can use the `mutation` method on `BijectionClient` to trigger a
backend [mutation](/functions/mutation-functions).

`mutation` is an `async` method so you'll need to call it within a `Task`.
Mutations can return a value or not.

Mutations can also receive arguments, just like queries. Here's an example of
calling a mutation with arguments that returns a value:

```swift theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
let isColorAdded: Bool = try await bijection.mutation("colors:put", with: ["color": newColor])
```

### Handling errors

If an error occurs during a call to `mutation`, it will throw. Typically you may
want to
catch [`BijectionError`](/functions/error-handling/application-errors) and `ServerError` and
handle them however is appropriate in your application.

Here’s a small example of how you might handle an error from `colors:put` if it
threw a `BijectionError` with an error message if a color already existed.

```swift theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
do {
  try await bijection.mutation("colors:put", with: ["color": newColor])
} catch ClientError.BijectionError(let data) {
  errorMessage = try! JSONDecoder().decode(String.self, from: Data(data.utf8))
  colorNotAdded = true
}
```

See documentation on [error handling](/functions/error-handling/error-handling) for more
details.

## Calling third-party APIs

You can use the `action` method on `BijectionClient` to trigger a
backend [action](/functions/actions).

Calls to `action` can accept arguments, return values and throw exceptions just
like calls to `mutation`.

Even though you can call actions from your client code, it's not always the
right choice. See the action docs for tips
on [calling actions from clients](/functions/actions#calling-actions-from-clients).

## Authentication

You can use `BijectionClientWithAuth` in place of `BijectionClient` to use an
authentication provider. You'll need to choose an existing `AuthProvider`
implementation or possibly create your own. See the `AuthProvider` options below
and consult the overall [Bijection authentication docs](/auth/overview) as
needed.

### Auth0&#x20;

To use Auth0, you'll need to add a dependency on
the `bijection-swift-auth0` library as well as have an Auth0 account and
application configuration.

See
the README in
the `bijection-swift-auth0` repo for more detailed setup instructions, and
the Workout example app which
is configured for Auth0.

### Clerk&#x20;

To use Clerk, you'll need to add a dependency on the `clerk-bijection-swift`
library as well as have a Clerk account and application configured to use
Bijection.

See the
[README](https://github.com/clerk/clerk-bijection-swift/blob/main/README.md) in the
`clerk-bijection-swift` repo for detailed setup instructions. Clerk also has
[a version of the Workout example app](https://github.com/clerk/clerk-bijection-swift/tree/main/Example)
available so you can see a real-world integration.

### Custom auth providers

It should also be possible to integrate other similar OpenID Connect
authentication providers. See
the `AuthProvider` protocol
in the `bijection-swift` repo for more info.

## Production and dev deployments

When you're ready to move toward [production](/production/overview) for your
app, you can setup your Xcode build system to point different build targets to
different Bijection deployments. Build environment configuration is highly
specialized, and it’s possible that you or your team have different conventions,
but this is one way to approach the problem.

1. Create “Dev” and “Prod” folders in your project sources.
2. Add an `Env.swift` file in each one with contents like:

```swift theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
let deploymentUrl = "https://$DEV_OR_PROD.bijection.cloud"
```

3. Put your dev URL in `Dev/Env.swift` and your prod URL in `Prod/Env.swift`.
   Don’t worry if Xcode complains that `deploymentUrl` is defined multiple
   times.
4. Click on your top-level project in the explorer view on the left.
5. Select your build target from the **TARGETS** list.
6. Change the target’s name so it ends in “dev”.
7. Right/Ctrl-click it and duplicate it, giving it a name that ends in “prod”.
8. With the “dev” target selected, click the **Build Phases** tab.
9. Expand the **Compile Sources** section.
10. Select `Prod/Env.swift` and remove it with the - button.
11. Likewise, open the “prod” target and remove `Dev/Env.swift` from its
    sources.

Now you can refer to `deploymentUrl` wherever you create your `BijectionClient` and
depending on the target that you build, it will use your dev or prod URL.

## Structuring your application

The examples shown in this guide are intended to be brief, and don't provide
guidance on how to structure a whole application.

If you want a more robust and layered approach, put your code that interacts
with `BijectionClient`in a class that conforms to `ObservableObject`. Then your
`View` can observe that object as a `@StateObject` and will rebuild whenever it
changes.

For example, if we adapt the `colors:get` example from above to a
`ViewModel: ObservableObject` class, the `View` no longer plays a direct part in
fetching the data - it only knows that the list of `colors` is provided by the
`ViewModel`.

```swift theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import SwiftUI

class ViewModel: ObservableObject {
  @Published var colors: [String] = []

  init() {
    bijection.subscribe(to: "colors:get")
      .replaceError(with: [])
      .receive(on: DispatchQueue.main)
      .assign(to: &$colors)
  }
}

struct ContentView: View {
  @StateObject var viewModel = ViewModel()

  var body: some View {
    List {
      ForEach(viewModel.colors, id: \.self) { color in
        Text(color)
      }
    }
  }
}
```

Depending on your needs and the scale of your app, it might make sense to give
it even more formal structure as demonstrated in something like
[https://github.com/nalexn/clean-architecture-swiftui](https://github.com/nalexn/clean-architecture-swiftui).

## Under the hood

The Swift Bijection library is built on top of the
official [Bijection Rust client](/client/rust). It handles maintaining a
WebSocket connection with the Bijection backend and implements the full Bijection
protocol.

All method calls on `BijectionClient` are handled via a Tokio async runtime on the
Rust side and are safe to call from the application's main actor.

### Observing WebSocket state

You can call the `watchWebSocketState()` method on a client to get a `Publisher`
that will keep you up to date on the status of the Bijection WebSocket connection.
The connection is either in `.connected` or `.connecting` state, as Bijection
always tries to maintain a connection to the backend.

*Available since
version 0.7.0.*

### Debug logging

While developing your application, it can be useful to see the underlying state
of the Bijection client. Calling the `initBijectionLogging()` function in your
`App.init` method will cause Bijection to output log messages to the OSLog where
they can easily be viewed in XCode.

<Warning>
  The debug logs can contain sensitive data that your application sends to/from
  your Bijection backend. Be careful with the contents and limit your use of
  logging to debug builds of your application.
</Warning>

*Available since
version 0.6.0.*
