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.
- Create, update and subscribe to changes on LiveObjects data structures: LiveMap and LiveCounter.
Authentication
An API key is required to authenticate with Ably. API keys are used either to authenticate directly with Ably using basic authentication, or to generate tokens for untrusted clients using token authentication.
Sign up for a free account and create your own API key in the dashboard or use the Control API to create an API key programmatically.
API keys and tokens have a set of capabilities 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 root 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 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.
Xcode
To follow this guide in Xcode, use a new iOS project with the SwiftUI App template. All code can be added directly to your ContentView.swift
file, inside the ContentView
struct. Use the .task
modifier with a do { … } catch { … }
inside to run the Ably code when the view appears. No additional files or setup are needed. All print
output will appear in Xcode's debug console (View > Debug Area > Activate Console, or press Cmd+Shift+C).
Install the Ably SDK and the LiveObjects plugin in your Xcode project:
- Paste
https://github.com/ably/ably-cocoa
in the Swift Packages search box (File → Add Package Dependencies). - Add the
Ably
product. - Paste
https://github.com/ably/ably-cocoa-liveobject-plugin
in the Swift Packages search box. - Add the
AblyLiveObjects
product.
Import the SDK and the LiveObjects plugin into your project:
1
2
import Ably
import AblyLiveObjects
Instantiate a client
Instantiate an Ably Realtime client from the Pub/Sub SDK, providing the LiveObjects plugin:
1
2
3
4
let clientOptions = ARTClientOptions(key: "demokey:*****")
clientOptions.plugins = [.liveObjects: AblyLiveObjects.Plugin.self]
let realtimeClient = ARTRealtime(options: clientOptions)
A ClientOptions
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 provide the .liveObjects
plugin so that the client can use LiveObjects functionality.
Create a channel
LiveObjects is managed and persisted on channels. To use LiveObjects, you must first create a channel with the correct channel mode flags:
OBJECT_SUBSCRIBE
- required to access objects on a channel.OBJECT_PUBLISH
- required to create and modify objects on a channel.
1
2
3
let channelOptions = ARTRealtimeChannelOptions()
channelOptions.modes = [.objectPublish, .objectSubscribe]
let channel = realtimeClient.channels.get("my_liveobjects_channel", options: channelOptions)
Next, you need to attach to the channel. Attaching to a channel starts an initial synchronization sequence where the objects on the channel are sent to the client.
1
2
3
4
5
6
7
8
9
try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, Error>) in
channel.attach { error in
if let error {
continuation.resume(throwing: error)
} else {
continuation.resume()
}
}
}
Get root object
The channel.objects
property gives access to the LiveObjects API for a channel.
Use it to get the root object, which is the entry point for accessing and persisting objects on a channel. The root object is a LiveMap
instance that always exists on a channel and acts as the top-level node in your object tree. You can get the root object using the getRoot()
function of LiveObjects:
1
2
// The getRoot call returns once the LiveObjects state is synchronized with the Ably system
let root = try await channel.objects.getRoot()
Create objects
You can create new objects using dedicated functions of the LiveObjects API at channel.objects
. To persist them on a channel and share them between clients, you must assign objects to a parent LiveMap
instance connected to the root object. The root object itself is a LiveMap
instance, so you can assign objects to the root and start building your object tree from there.
1
2
3
4
5
let visitsCounter = try await channel.objects.createCounter()
let reactionsMap = try await channel.objects.createMap()
try await root.set(key: "visits", value: .liveCounter(visitsCounter))
try await root.set(key: "reactions", value: .liveMap(reactionsMap))
Subscribe to updates
Subscribe to realtime updates to objects on a channel. You will be notified when an object is updated by other clients or by you.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
try visitsCounter.subscribe { _, _ in
do {
print("Visits counter updated: \(try visitsCounter.value)")
} catch {
// Error handling of visitsCounter.value omitted for brevity
}
}
try reactionsMap.subscribe { _, _ in
do {
print("Reactions map updated: \(try reactionsMap.entries)")
} catch {
// Error handling of reactionsMap.entries omitted for brevity
}
}
Update objects
Update objects using mutation methods. All subscribers (including you) will be notified of the changes when you update an object:
1
2
3
4
5
6
7
8
9
10
11
try await visitsCounter.increment(amount: 5)
// console: "Visits counter updated: 5.0"
try await visitsCounter.decrement(amount: 2)
// console: "Visits counter updated: 3.0"
try await reactionsMap.set(key: "like", value: 10)
// console: "Reactions map updated: [(key: "like", value: AblyLiveObjects.LiveMapValue.number(10.0))]"
try await reactionsMap.set(key: "love", value: 5)
// console: "Reactions map updated: [(key: "like", value: AblyLiveObjects.LiveMapValue.number(10.0)), (key: "love", value: AblyLiveObjects.LiveMapValue.number(5.0))]"
try await reactionsMap.remove(key: "like")
// console: "Reactions map updated: [(key: "love", value: AblyLiveObjects.LiveMapValue.number(5.0))]"
Next steps
This quickstart introduced the basic concepts of LiveObjects and demonstrated how it works. The next steps are to:
- Read more about LiveCounter and LiveMap.
- Learn about Batching Operations.
- Learn about Objects Lifecycle Events.
- Add Typings for your LiveObjects.