# Getting started: LiveObjects in Swift
This guide shows how to integrate Ably LiveObjects into your Swift application.
You will learn how to:
* Create an Ably account and get an API key for authentication.
* Install the Ably Pub/Sub SDK.
* Create a channel with LiveObjects functionality enabled.
* Use the [PathObject API](https://ably.com/docs/liveobjects/concepts/path-object.md) to access objects on a channel.
* Create, update and subscribe to changes on LiveObjects data structures: [LiveMap](https://ably.com/docs/liveobjects/map.md) and [LiveCounter](https://ably.com/docs/liveobjects/counter.md).
## Authentication
An [API key](https://ably.com/docs/auth.md#api-keys) is required to authenticate with Ably. API keys are used either to authenticate directly with Ably using [basic authentication](https://ably.com/docs/auth/basic.md), or to generate tokens for untrusted clients using [token authentication](https://ably.com/docs/auth/token.md).
[Sign up](https://ably.com/sign-up) for a free account and create your own API key in the [dashboard](https://ably.com/dashboard) or use the [Control API](https://ably.com/docs/platform/account/control-api.md) to create an API key programmatically.
API keys and tokens have a set of [capabilities](https://ably.com/docs/auth/capabilities.md) assigned to them that specify which operations can be performed on which resources. The following capabilities are available for LiveObjects:
* `object-subscribe` - grants clients read access to LiveObjects, allowing them to get the channel object and subscribe to updates.
* `object-publish` - grants clients write access to LiveObjects, allowing them to perform mutation operations on objects.
To use LiveObjects, an API key must have at least the `object-subscribe` capability. With only this capability, clients will have read-only access, preventing them from calling mutation methods on LiveObjects.
For the purposes of this guide, make sure your API key includes both `object-subscribe` and `object-publish` [capabilities](https://ably.com/docs/auth/capabilities.md) to allow full read and write access.
## Install Ably Pub/Sub SDK
LiveObjects is available as part of the Ably Pub/Sub SDK via the dedicated LiveObjects plugin. The plugin ships as the `AblyLiveObjects` product of the `ably-cocoa` package from version 1.3.0 onwards, and is available through Swift Package Manager only. There is no separate package or version to install: the plugin is versioned and released as part of `ably-cocoa`.
The LiveObjects plugin requires a minimum deployment target of iOS 14, macOS 11, or tvOS 14, and Xcode 16.3 or later.
Add the Ably SDK and the LiveObjects plugin to your Xcode project:
1. Select File → Add Package Dependencies.
2. Paste `https://github.com/ably/ably-cocoa` in the search box.
3. Set the dependency rule to version 1.4.0 or later.
4. Add both the `Ably` and `AblyLiveObjects` products to your target.
To install the plugin in another Swift package instead, add both products to your target's dependencies in `Package.swift`:
### Swift
```
dependencies: [
.package(url: "https://github.com/ably/ably-cocoa", from: "1.4.0"),
],
targets: [
.target(
name: "MyTarget",
dependencies: [
.product(name: "Ably", package: "ably-cocoa"),
.product(name: "AblyLiveObjects", package: "ably-cocoa"),
]
),
]
```
For the complete installation notes, platform requirements, usage overview and example app, see the [LiveObjects section of the ably-cocoa README](https://github.com/ably/ably-cocoa#liveobjects).
Import the SDK and the LiveObjects plugin into your project:
### Swift
```
import Ably
import AblyLiveObjects
```
## Instantiate a client
Instantiate an Ably Realtime client from the Pub/Sub SDK, providing the LiveObjects plugin:
### Swift
```
let clientOptions = ARTClientOptions(key: "your-api-key")
clientOptions.plugins = [.liveObjects: AblyLiveObjects.Plugin.self]
let realtime = ARTRealtime(options: clientOptions)
```
A [`ClientOptions`](https://ably.com/docs/api/realtime-sdk.md#client-options) object may be passed to the Pub/Sub SDK instance to further customize the connection, however at a minimum you must set an API key and register the LiveObjects plugin through `clientOptions.plugins` so that the client can use LiveObjects functionality.
## Create a channel
LiveObjects is managed and persisted on [channels](https://ably.com/docs/channels.md). To use LiveObjects, you must first create a channel with the correct [channel mode flags](https://ably.com/docs/channels/options.md#modes):
* `OBJECT_SUBSCRIBE` - required to access objects on a channel.
* `OBJECT_PUBLISH` - required to create and modify objects on a channel.
### Swift
```
let channelOptions = ARTRealtimeChannelOptions()
channelOptions.modes = [.objectPublish, .objectSubscribe]
let channel = realtime.channels.get("test-channel", options: channelOptions)
```
## Get the channel object
The [`channel.object`](https://ably.com/docs/api/realtime-sdk/channels.md#object) property gives access to the LiveObjects API for a channel.
Use `channel.object.get()` to obtain the channel object. The channel object is a [`LiveMap`](https://ably.com/docs/liveobjects/map.md) that always exists on a channel and acts as the top-level entry point for accessing and persisting objects. It is returned as a [`LiveMapPathObject`](https://ably.com/docs/liveobjects/concepts/path-object.md#get), which provides a path-based API for accessing and manipulating the object hierarchy.
`channel.object.get()` is an `async` function that suspends with `try await` until the LiveObjects state is synchronized with the Ably system. Reads are synchronous and local:
### Swift
```
let rootObject = try await channel.object.get()
```
## Create and assign objects
You can create and assign objects using the `LiveMap.create()` and `LiveCounter.create()` static methods. These methods return a blueprint describing the object to create; the actual object is created when you assign it to a key with `set()`. Wrap a blueprint in `.liveCounter(...)` or `.liveMap(...)` when passing it to `set()`, while primitive values such as strings and numbers can be passed directly:
### Swift
```
// Create a LiveCounter with initial value 0
let visits = LiveCounter.create(initialCount: 0)
// Assign it to the 'visits' key on the channel object
try await rootObject.set(key: "visits", value: .liveCounter(visits))
// Create a LiveMap with initial entries
let reactions = LiveMap.create(entries: [
"likes": 0,
"hearts": 0,
])
// Assign it to the 'reactions' key on the channel object
try await rootObject.set(key: "reactions", value: .liveMap(reactions))
// Infer types for the assigned objects
let visitsCounter = rootObject.get(key: "visits").asLiveCounter()
let reactionsMap = rootObject.get(key: "reactions").asLiveMap()
```
`rootObject.get(key:)` returns a general [`PathObject`](https://ably.com/docs/liveobjects/concepts/path-object.md) that doesn't yet know the type of the value it points to. Call one of the `as*` methods, such as `asLiveCounter()` or `asLiveMap()`, to work with the value as a specific type. These casts are always safe to call: they never throw, even if the value at the path has a different type. Learn more about [Type inference](https://ably.com/docs/liveobjects/typing.md#type-inference).
## Subscribe to updates
Subscribe to realtime updates using the `subscribe()` method on a `PathObject`. You will be notified when the object at that path is updated by other clients or by you:
### Swift
```
// Subscribe to counter updates
let counterSubscription = try visitsCounter.subscribe { event in
guard let value = try? event.object.asLiveCounter().value() else { return }
print("Visits counter updated: \(value)")
}
// Subscribe to map updates
let mapSubscription = try reactionsMap.subscribe { event in
guard let json = try? event.object.compactJson() else { return }
print("Reactions updated: \(json)")
}
```
The subscription callback receives an event that exposes:
- `object`: A `PathObject` pointing to the path where the change occurred.
- `message`: The `ObjectMessage` that carried the operation that led to the change (nullable).
The `subscribe()` method also returns a `Subscription` object. When you no longer want to receive updates, call `unsubscribe()` on it:
### Swift
```
// Keep the Subscription returned by subscribe()
let subscription = try visitsCounter.subscribe { event in
guard let value = try? event.object.asLiveCounter().value() else { return }
print("Visits counter updated: \(value)")
}
// Later, stop receiving updates
subscription.unsubscribe()
```
Every `PathObject` also exposes an `events()` [`AsyncStream`](https://developer.apple.com/documentation/swift/asyncstream), so you can consume updates with `for await`, which is often the more idiomatic pattern in Swift. Breaking out of the loop, or cancelling the enclosing task, automatically unsubscribes:
### Swift
```
for await event in try visitsCounter.events() {
guard let value = try? event.object.asLiveCounter().value() else { continue }
print("Visits counter updated: \(value)")
}
```
## Update objects
Update objects using mutation methods on `PathObject`. All subscribers (including you) will be notified of the changes:
### Swift
```
// Update counter
try await visitsCounter.increment(amount: 5)
// console: Visits counter updated: 5.0
try await visitsCounter.decrement(amount: 2)
// console: Visits counter updated: 3.0
// Update map
try await reactionsMap.set(key: "likes", value: 10)
// console: Reactions updated: {"likes":10.0,"hearts":0.0}
try await reactionsMap.set(key: "hearts", value: 5)
// console: Reactions updated: {"likes":10.0,"hearts":5.0}
try await reactionsMap.remove(key: "likes")
// console: Reactions updated: {"hearts":5.0}
```
## Next steps
This quickstart introduced the basic concepts of LiveObjects and demonstrated how the path-based API works. The next steps are to:
* Learn about the [PathObject](https://ably.com/docs/liveobjects/concepts/path-object.md) and [Instance](https://ably.com/docs/liveobjects/concepts/instance.md) APIs.
* Read more about [LiveCounter](https://ably.com/docs/liveobjects/counter.md) and [LiveMap](https://ably.com/docs/liveobjects/map.md).
* Learn about [Objects Lifecycle Events](https://ably.com/docs/liveobjects/lifecycle.md).
* Learn about [Type inference](https://ably.com/docs/liveobjects/typing.md) for your LiveObjects.
## Related Topics
- [JavaScript](https://ably.com/docs/liveobjects/quickstart/javascript.md): A getting started guide to learn the basics of integrating the Ably LiveObjects product into your JavaScript application.
- [Java](https://ably.com/docs/liveobjects/quickstart/java.md): A quickstart guide to learn the basics of integrating the Ably LiveObjects product into your Java application.
## Documentation Index
To discover additional Ably documentation:
1. Fetch [llms.txt](https://ably.com/llms.txt) for the canonical list of available pages.
2. Identify relevant URLs from that index.
3. Fetch target pages as needed.
Avoid using assumed or outdated documentation paths.