Skip to main content

Messaging – Subscribe & Unsubscribe

Overview

Subscribing allows a Swift application to receive messages published to specific topics or topic patterns. When a subscription is active, the RelayX client opens a live message stream and delivers messages to your handler as they arrive, in real-time.

Subscriptions are how applications react to events in real time. They are commonly used for user events, telemetry, notifications, and system signals. A single client can maintain multiple subscriptions at the same time, each scoped to a different topic or pattern.

Unsubscribing stops message delivery for a topic. This releases resources on both the client and the RelayX backend and should be done when a subscription is no longer needed.

How This Works

When you call the subscribe API, the SDK registers your interest in a topic or topic pattern with the RelayX backend. From that point forward, any message published to a matching topic is delivered to your callback function.

Delivery happens asynchronously. The publisher does not know who is subscribed, and subscribers do not affect publish behavior. Each subscription operates independently.

If the client disconnects due to a network issue, the SDK attempts to reconnect automatically. When reconnection succeeds, messages published while the client was offline are replayed for all active subscriptions. This replay applies only to subscriptions that existed before the disconnect.

API Usage

Subscribing to a Topic

Use the on(topic:listener:) method to subscribe.

Note: on() is an async function and must be called with await from an async context.

Parameters

  • topic (String): A valid topic name or topic pattern. Wildcards * and > are supported.
  • listener (MessageListener): An object conforming to the MessageListener protocol. The onMessage(_:) method is invoked for every received message.

Return Value

  • Returns true if the subscription was created successfully.
  • Returns false if:
    • The topic is already subscribed
    • The SDK failed to create the subscription

Message Dictionary Structure

// The message passed to onMessage(_:) is a dictionary [String: Any]:
[
"id": String, // Message ID
"topic": String, // Topic the message was sent to
"data": Any // The actual message payload (String, Number, or Dictionary)
]

Unsubscribing from a Topic

Use the off(topic:) method to unsubscribe.

Note: off() is an async function and must be called with await from an async context.

Parameters

  • topic (String): The exact topic or pattern previously subscribed to.

Return Value

  • Returns true if the subscription was removed successfully.
  • Returns false if the unsubscribe operation failed.

Code Example

import Realtime

// Define a listener for temperature messages
class TemperatureListener: MessageListener {
func onMessage(_ message: Any) {
// message is a dictionary containing the message data
if let msg = message as? [String: Any] {
print("Received message: \(msg["data"] ?? "N/A")")
print("From topic: \(msg["topic"] ?? "N/A")")
print("Message ID: \(msg["id"] ?? "N/A")")
}
}
}

// Define a listener for wildcard temperature subscriptions
class WildcardTemperatureListener: MessageListener {
func onMessage(_ message: Any) {
if let msg = message as? [String: Any] {
print("Temperature update: \(msg["data"] ?? "N/A")")

// Messages from topics matching `devices.*.temperature` will be received here
// For example:
// - devices.kitchen.temperature
// - devices.bedroom.temperature
}
}
}

Task {
do {
// Initialize and connect to Realtime
let realtime = try Realtime(apiKey: "<API KEY>", secret: "<SECRET KEY>")
try realtime.prepare(staging: false, opts: ["debug": true])
try await realtime.connect()

// Subscribe to a specific topic
let tempListener = TemperatureListener()
let subscribed = try await realtime.on(topic: "devices.kitchen.temperature", listener: tempListener)

if !subscribed {
print("Failed to subscribe to topic")
}

// Subscribe using wildcards
let wildcardListener = WildcardTemperatureListener()
try await realtime.on(topic: "devices.*.temperature", listener: wildcardListener)

// Your application logic here...

// Unsubscribe from a topic
let unsubscribed = try await realtime.off(topic: "devices.kitchen.temperature")

if !unsubscribed {
print("Failed to unsubscribe from topic")
}

} catch {
print("Error: \(error)")
}
}

Failure & Edge Cases

Network interruptions If the connection drops, the SDK automatically enters a reconnecting state. Messages published during this period are replayed after reconnection for all active subscriptions.

Client crashes If the iOS app exits, subscriptions are lost. On restart, subscriptions must be recreated explicitly.

Invalid topics Subscription attempts fail if the topic name is invalid or violates topic naming rules. The SDK throws an error immediately. More information here

Duplicate delivery In rare failure scenarios, messages may be delivered more than once. Subscriber logic must be idempotent.

Common Mistakes

Assuming handlers run exactly once RelayX provides at-least-once delivery. Your handler may be invoked more than once for the same message.

Forgetting to unsubscribe Leaving unused subscriptions active consumes resources and may lead to unexpected message handling.

Publishing to wildcards Wildcards are supported only for subscribing, not publishing. Publishing to wildcard topics does not deliver messages.

Ignoring reconnect behavior Applications that do not expect replayed messages may incorrectly process duplicates after reconnect.

Notes & Limitations

  • Wildcards are supported only in subscriptions.
  • Message replay applies only to subscriptions that existed before disconnect.
  • Subscription callbacks must be fast and non-blocking to avoid backpressure.


Need Help?

Join our Discord server, post your concern & someone from our team will help you out ✌️