# Topic (/zh-CN/api-reference/rtm/swift/topic)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

Topic 是 Stream Channel 中的数据流管理机制。用户可以在 Stream Channel 中利用此特性进行数据流的订阅、分发、事件通知等。

:::info[信息]
Topic 只存在于 Stream Channel。所以用户在使用相关特性之前，需要先创建一个 `AgoraRtmStreamChannel` 对象实例。
:::

想要了解 Topic 的更多特性，可以查看：

- [Topic](/zh-CN/realtime-media/rtm/build/channels-and-topics/topics/topic-basic)

## joinTopic [#jointopic]

### 接口描述 [#接口描述]

加入 Topic 的目的在于注册成为该 Topic 的消息发布者之一，从而让用户具备发送消息的能力。是否执行该操作都不影响该用户是否成为该 Topic 的订阅者。

:::info[信息]
- 当前 RTM 支持单客户端在同一个 Stream Channel 中同时加入 8 个 Topic。
- 在执行此操作之前，用户需要首先创建 `AgoraRtmStreamChannel` 对象实例，并调用 `join` 方法加入频道，详见[频道](/zh-CN/realtime-media/rtm/build/channels-and-topics/channel-basic)。
:::

成功加入 Topic 后，订阅该 Topic 并添加事件监听的用户会收到 `remoteJoinTopic` 类型的 `didReceiveTopicEvent` 事件通知。详见[事件监听](/zh-CN/api-reference/rtm/swift/configuration#事件监听)。

### 接口方法 [#接口方法]

你可以通过以下方式调用 `joinTopic` 方法：

```swift
joinTopic(
    _ topic: String,
    option: AgoraRtmJoinTopicOption?
)   async -> (AgoraRtmCommonResponse?, AgoraRtmErrorInfo?)
```

```swift
joinTopic(
    _ topic: String,
    option: AgoraRtmJoinTopicOption?,
    completion completionBlock: AgoraRtmOperationBlock? = nil
)
```

| 参数 | 类型 | 必填 | 默认值 | 描述 |
| --- | --- | --- | --- | --- |
| `topic` | String | 必填 | - | Topic 名称。 |
| `option` | `AgoraRtmJoinTopicOption` | 选填 | - | 加入 Topic 选项。 |
| `completion` | `AgoraRtmOperationBlock` | 选填 | - | [topic-swift-html-0-3-4 details](#table-slot-topic-swift-html-0-3-4) |

<a id="table-slot-topic-swift-html-0-3-4"></a>

**topic-swift-html-0-3-4 details**

调用结果回调：

- 调用成功：在 `response` 参数中返回 `AgoraRtmCommonResponse` 数据，在 `errorInfo` 参数中返回 `nil`。
- 调用失败：在 `response` 参数中返回 `nil`，在 `errorInfo` 参数中返回错误信息。

`AgoraRtmJoinTopicOption` 数据类型包含以下属性：

| 属性            | 类型                  | 必填 | 默认值               | 描述   |
| -------------- | ---------------- | --- | --------------- | ------------ |
| `qos`           | `AgoraRtmMessageQos` | 选填 | `.ordered` | 定义此 Topic 中传输数据是否保序。详见 [`AgoraRtmMessageQos`](/zh-CN/api-reference/rtm/swift/enumv#messageqos)。            |
| `priority`      | `AgoraRtmMessagePriority`   | 选填 | `.normal`    | 定义此 Topic 中传输数据的优先级（相比于同频道中的其他 Topic）。详见 [`AgoraRtmMessagePriority`](/zh-CN/api-reference/rtm/swift/enumv#messagepriority)。 |
| `meta`          | String              | 选填 | -                    | 加入 Topic 时携带的其他辅助信息。                |
| `syncWithMedia` | Bool                  | 选填 | `false`              | 此 Topic 中发送的数据是否与共频道的 RTC 音视频数据流实现数据同步（时间戳对齐）。    |

### 基本用法 [#基本用法]

```swift tab="async-await"
// async-await
let topic = "exampleTopic"
let joinOption = AgoraRtmJoinTopicOption()
joinOption.priority = .high
joinOption.syncWithMedia = false

let (response, error) = await stChannel.joinTopic(topic, option: joinOption)
if let errorInfo = error {
    // Handle error
    print("Failed to join topic with error: \(errorInfo.reason)")
} else if let joinTopicResponse = response {
    // Handle success
    print("Successfully joined topic.")
} else {
    // Handle unknown error
    print("Unknown error occurred while joining the topic.")
}
```

```swift tab="callback"
// callback
let topic = "exampleTopic"
let joinOption = AgoraRtmJoinTopicOption()
joinOption.priority = .high
joinOption.syncWithMedia = false

stChannel.joinTopic(topic, option: joinOption) { (response, error) in
    if let errorInfo = error {
        // Handle error
        print("Failed to join topic with error: \(errorInfo.reason)")
    } else if let joinTopicResponse = response {
        // Handle success
        print("Successfully joined topic.")
    } else {
        // Handle unknown error
        print("Unknown error occurred while joining the topic.")
    }
}
```

## publishTopicMessage [#publishtopicmessage]

### 接口描述 [#接口描述-1]

`publishTopicMessage` 方法用于向 Topic 发送消息，频道中订阅此 Topic 及此消息发布者的用户会在 100 毫秒内收到此消息。调用 `publishTopicMessage` 方法需要用户首先加入 Stream Channel 并且通过调用 `joinTopic` 方法注册成为该 Topic 的消息发布者。

用户发送的消息在传输的过程中会被 TLS 加密，数据链路加密默认开启且无法关闭。用户也可以在出初始化的时候开启端侧加密，以获得更高的数据安全等级，详见[初始配置](/zh-CN/api-reference/rtm/swift/configuration)。

### 接口方法 [#接口方法-1]

你可以通过以下方式调用 `publishTopicMessage`[1/2] 和 `publishTopicMessage`[2/2] 方法：

- 发送字符串消息：

  ```swift
  publishTopicMessage(
      topic: String,
      message: String,
      option options: AgoraRtmTopicMessageOptions?
  )   async -> (AgoraRtmCommonResponse?, AgoraRtmErrorInfo?)
  ```

  ```swift
  publishTopicMessage(
      topic: String,
      message: String,
      option options: AgoraRtmTopicMessageOptions?,
      completion completionBlock: AgoraRtmOperationBlock? = nil
  )
  ```

- 发送二进制消息：

  ```swift
  publishTopicMessage(
      topic: String,
      ata: Data,
      option options: AgoraRtmTopicMessageOptions?
  )   async -> (AgoraRtmCommonResponse?, AgoraRtmErrorInfo?)
  ```

  ```swift
  publishTopicMessage(
      topic: String,
      data: Data,
      option options: AgoraRtmTopicMessageOptions?,
      completion completionBlock: AgoraRtmOperationBlock? = nil
  )
  ```

| 参数 | 类型 | 必填 | 默认值 | 描述 |
| --- | --- | --- | --- | --- |
| `topic` | String | 必填 | - | Topic 名称。 |
| `message` | String | 必填 | - | 在 `publishTopicMessage`[1/2] 方法中发布 String 型消息负载。 |
| `data` | Data | 必填 | - | 在 `publishTopicMessage`[2/2] 方法中发布 Byte 型消息负载。 |
| `options` | `AgoraRtmTopicMessageOptions` | 选填 | - | 消息选项。 |
| `completion` | `AgoraRtmOperationBlock` | 选填 | - | [topic-swift-html-1-5-4 details](#table-slot-topic-swift-html-1-5-4) |

<a id="table-slot-topic-swift-html-1-5-4"></a>

**topic-swift-html-1-5-4 details**

调用结果回调：

- 调用成功：在 `response` 参数中返回 `AgoraRtmCommonResponse` 数据，在 `errorInfo` 参数中返回 `nil`。
- 调用失败：在 `response` 参数中返回 `nil`，在 `errorInfo` 参数中返回错误信息。

<a id="options"></a>
`AgoraRtmTopicMessageOptions` 数据类型包含以下属性：

| 属性         | 类型               | 是否必填 | 默认值 | 描述          |
| ----------- | ----------------- | ------- | ----- | -------- |
| `sendTs`     | `UInt64` | 选填     | `0`    | 消息发送时间戳。只有在 `joinTopic` 中设置 `syncWithMedia = true` 时，该参数才有效，SDK 会根据此时间戳与 RTC 音视频数据流进行数据同步。 |
| `customType` | String           | 必填     | -      | 用户自定义字段。仅支持 NSString 型。   |

### 接口方法 [#接口方法-2]

示例 1：向指定频道发送 String 消息

```swift tab="async-await"
// async-await
let topic = "exampleTopic"
let message = "Hello, Agora!"
let messageOptions = AgoraRtmTopicMessageOptions()
messageOption.customType = "PlainText"

let (response, error) = await stChannel.publishTopicMessage(
    topic: topic,
    message: message,
    option: messageOptions
)
if let errorInfo = error {
    // Handle error
    print("Failed to publish message with error: \(errorInfo.reason)")
} else if let publishResponse = response {
    // Handle success
    print("Message published successfully.")
} else {
    // Handle unknown error
    print("Unknown error occurred while publishing the message.")
}
```

```swift tab="callback"
// callback
let topic = "exampleTopic"
let message = "Hello, Agora!"
let messageOptions = AgoraRtmTopicMessageOptions()
messageOption.customType = "PlainText"

stChannel.publishTopicMessage(
    topic: topic,
    message: message,
    option: messageOptions
) { (response, error) in
    if let errorInfo = error {
        // Handle error
        print("Failed to publish message with error: \(errorInfo.reason)")
    } else if let publishResponse = response {
        // Handle success
        print("Message published successfully.")
    } else {
        // Handle unknown error
        print("Unknown error occurred while publishing the message.")
    }
}
```

示例 2：向指定频道发送 Byte 消息

```swift tab="async-await"
// async-await
let topic = "exampleTopic"
let messageOptions = AgoraRtmTopicMessageOptions()
messageOption.customType = "BinaryData"
let byteArray: [UInt8] = [0x00, 0x01, 0x02, 0x03]
let binaryData = Data(byteArray)

let (response, error) = await stChannel.publishTopicMessage(
    topic: topic,
    ata: binaryData,
    option: messageOptions
)
if let errorInfo = error {
    // Handle error
    print("Failed to publish binary data with error: \(errorInfo.reason)")
} else if let publishResponse = response {
    // Handle success
    print("Binary data published successfully.")
} else {
    // Handle unknown error
    print("Unknown error occurred while publishing the binary data.")
}
```

```swift tab="callback"
// callback
let topic = "exampleTopic"
let messageOptions = AgoraRtmTopicMessageOptions()
messageOption.customType = "BinaryData"
let byteArray: [UInt8] = [0x00, 0x01, 0x02, 0x03]
let binaryData = Data(byteArray)

stChannel.publishTopicMessage(
    topic: topic,
    ata: binaryData,
    option: messageOptions
) { (response, error) in
    if let errorInfo = error {
        // Handle error
        print("Failed to publish binary data with error: \(errorInfo.reason)")
    } else if let publishResponse = response {
        // Handle success
        print("Binary data published successfully.")
    } else {
        // Handle unknown error
        print("Unknown error occurred while publishing the binary data.")
    }
}
```

## leaveTopic [#leavetopic]

### 接口描述 [#接口描述-2]

当你不再需要向某个 Topic 发布消息，你可以调用 `leaveTopic` 方法取消注册为该 Topic 的消息发布者，从而释放资源。该方法不影响你是否订阅该 Topic，也不影响其他用户对该 Topic 的任何操作。

成功调用该方法后，订阅该频道并开启事件监听的用户会收到 `remoteLeaveTopic` 类型的 `didReceiveTopicEvent` 事件通知，详见[事件监听](/zh-CN/api-reference/rtm/swift/configuration#事件监听)。

### 接口方法 [#接口方法-3]

你可以通过以下方式调用 `leaveTopic` 方法：

```swift
leaveTopic(
    _ topic: String
)   async -> (AgoraRtmCommonResponse?, AgoraRtmErrorInfo?)
```

```swift
leaveTopic(
    _ topic: String,
    completion completionBlock: AgoraRtmOperationBlock? = nil
)
```

| 参数 | 类型 | 必填 | 默认值 | 描述 |
| --- | --- | --- | --- | --- |
| `topic` | String | 必填 | - | Topic 名称。 |
| `completion` | `AgoraRtmOperationBlock` | 选填 | - | [topic-swift-html-2-2-4 details](#table-slot-topic-swift-html-2-2-4) |

<a id="table-slot-topic-swift-html-2-2-4"></a>

**topic-swift-html-2-2-4 details**

调用结果回调：

- 调用成功：在 `response` 参数中返回 `AgoraRtmCommonResponse` 数据，在 `errorInfo` 参数中返回 `nil`。
- 调用失败：在 `response` 参数中返回 `nil`，在 `errorInfo` 参数中返回错误信息。

### 基本用法 [#基本用法-1]

```swift tab="async-await"
// async-await
let topic = "exampleTopic"

let (response, error) = await stChannel.leaveTopic(topic)
if let errorInfo = error {
    // Handle error
    print("Failed to leave topic with error: \(errorInfo.reason)")
} else if let leaveTopicResponse = response {
    // Handle success
    print("Successfully left topic.")
} else {
    // Handle unknown error
    print("Unknown error occurred while leaving the topic.")
}
```

```swift tab="callback"
// callback
let topic = "exampleTopic"

stChannel.leaveTopic(topic) { (response, error) in
    if let errorInfo = error {
        // Handle error
        print("Failed to leave topic with error: \(errorInfo.reason)")
    } else if let leaveTopicResponse = response {
        // Handle success
        print("Successfully left topic.")
    } else {
        // Handle unknown error
        print("Unknown error occurred while leaving the topic.")
    }
}
```

## subscribeTopic [#subscribetopic]

### 接口描述 [#接口描述-3]

加入频道后，你可以调用 `subscribeTopic` 方法订阅该频道中 Topic 的消息发布者。

`subscribeTopic` 为增量方法。例如，第一次调用该方法时，订阅消息发布者列表为 `[UserA, UserB]`，第二次调用该方法时，订阅消息发布者列表为 `[UserB, UserC]`，则最后成功订阅的结果是 `[UserA, UserB, UserC]`。

同一个用户在同一个频道中最多只能同时订阅 50 个 Topic，且每个 Topic 中最多只能订阅 64 个消息发布者。详见 [API 调用限制](/zh-CN/realtime-media/rtm/reference/usage-limits-and-errors/api-limits)。

### 接口方法 [#接口方法-4]

你可以通过以下方式调用 `subscribeTopic` 方法：

```swift
subscribeTopic(
    _ topic: String,
    option: AgoraRtmTopicOption?
)   async -> (AgoraRtmTopicSubscriptionResponse?, AgoraRtmErrorInfo?)
```

```swift
subscribeTopic(
    _ topic: String,
    option: AgoraRtmTopicOption?,
    completion completionBlock: AgoraRtmTopicSubscriptionBlock? = nil
)
```

| 参数 | 类型 | 必填 | 默认值 | 描述 |
| --- | --- | --- | --- | --- |
| `topic` | String | 必填 | - | Topic 名称。 |
| `option` | `AgoraRtmTopicOption` | 选填 | - | 订阅 Topic 选项。 |
| `completion` | `AgoraRtmTopicSubscriptionBlock` | 选填 | - | [topic-swift-html-3-3-4 details](#table-slot-topic-swift-html-3-3-4) |

<a id="table-slot-topic-swift-html-3-3-4"></a>

**topic-swift-html-3-3-4 details**

调用结果回调：

- 调用成功：在 `response` 参数中返回 `AgoraRtmTopicSubscriptionResponse` 数据，在 `errorInfo` 参数中返回 `nil`。
- 调用失败：在 `response` 参数中返回 `nil`，在 `errorInfo` 参数中返回错误信息。

`AgoraRtmTopicOption` 数据类型包含以下属性：

| 属性    | 类型       | 必填 | 默认值 | 描述            |
| ------ | --------- | --- | ----- | --------- |
| `users` | `[String]` | 选填 | -      | 需要订阅的消息发布者（Publisher）的 `UserId` 列表，如果不设置，则默认随机订阅不超过 64 个用户。 |

`AgoraRtmTopicSubscriptionResponse` 数据类型包含如下属性：

|      属性      |    类型    | 描述                 |
| ----------- | ------- | ------ |
| `succeedUsers` | `[String]` | 订阅成功的用户列表。 |
| `failedUsers`  | `[String]` | 订阅失败的用户列表。 |

### 基本用法 [#基本用法-2]

示例 1：订阅 Topic 中指定的消息发布者

```swift tab="async-await"
// async-await
let topic = "exampleTopic"
let topicOption = AgoraRtmTopicOption()                 // Optional, configure if needed
topicOption.users = ["user1", "user2"]                  // Specify users to subscribe to

let (response, error) = await stChannel.subscribeTopic(topic, option: topicOption)
if let errorInfo = error {
    // Handle error
    print("Failed to subscribe to topic with error: \(errorInfo.reason)")
} else if let subscriptionResponse = response {
    // Handle success
    print("Successfully subscribed to topic.")
} else {
    // Handle unknown error
    print("Unknown error occurred while subscribing to the topic.")
}
```

```swift tab="callback"
// callback
let topic = "exampleTopic"
let topicOption = AgoraRtmTopicOption()               // Optional
topicOption.users = ["user1", "user2"]                // Specify users to subscribe to

stChannel.subscribeTopic(topic, option: topicOption) { (response, error) in
    if let errorInfo = error {
        // Handle error
        print("Failed to subscribe to topic with error: \(errorInfo.reason)")
    } else if let subscriptionResponse = response {
        // Handle success
        print("Successfully subscribed to topic.")
    } else {
        // Handle unknown error
        print("Unknown error occurred while subscribing to the topic.")
    }
}
```

示例 2：随机订阅 Topic 中的 64 个消息发布者

```swift tab="async-await"
// async-await
let topic = "exampleTopic"

let (response, error) = await stChannel.subscribeTopic(topic, option: nil)
if let errorInfo = error {
    // Handle error
    print("Failed to subscribe to topic with error: \(errorInfo.reason)")
} else if let subscriptionResponse = response {
    // Handle success
    print("Successfully subscribed to topic.")
} else {
    // Handle unknown error
    print("Unknown error occurred while subscribing to the topic.")
}
```

```swift tab="callback"
// callback
let topic = "exampleTopic"

stChannel.subscribeTopic(topic, option: nil) { (response, error) in
    if let errorInfo = error {
        // Handle error
        print("Failed to subscribe to topic with error: \(errorInfo.reason)")
    } else if let subscriptionResponse = response {
        // Handle success
        print("Successfully subscribed to topic.")
    } else {
        // Handle unknown error
        print("Unknown error occurred while subscribing to the topic.")
    }
}
```

## unsubscribeTopic [#unsubscribetopic]

### 接口描述 [#接口描述-4]

如果你对某个 Topic 不再感兴趣，或者不再需要订阅 Topic 中的一个或多个消息发布者，你可以调用 `unsubscribeTopic` 方法取消订阅该 Topic 或取消订阅该 Topic 中指定的消息发布者。

### 接口方法 [#接口方法-5]

你可以通过以下方式调用 `unsubscribeTopic` 方法：

```swift
unsubscribeTopic(
    _ topic: String,
    option: AgoraRtmTopicOption?
)   async -> (AgoraRtmCommonResponse?, AgoraRtmErrorInfo?)
```

```swift
unsubscribeTopic(
    _ topic: String,
    option: AgoraRtmTopicOption?,
    completion completionBlock: AgoraRtmOperationBlock? = nil
)
```

| 参数 | 类型 | 必填 | 默认值 | 描述 |
| --- | --- | --- | --- | --- |
| `topic` | String | 必填 | - | Topic 名称。 |
| `options` | `AgoraRtmTopicOption` | 选填 | - | 取消订阅 Topic 选项。 |
| `completion` | `AgoraRtmOperationBlock` | 选填 | - | [topic-swift-html-4-3-4 details](#table-slot-topic-swift-html-4-3-4) |

<a id="table-slot-topic-swift-html-4-3-4"></a>

**topic-swift-html-4-3-4 details**

调用结果回调：

- 调用成功：在 `response` 参数中返回 `AgoraRtmCommonResponse` 数据，在 `errorInfo` 参数中返回 `nil`。
- 调用失败：在 `response` 参数中返回 `nil`，在 `errorInfo` 参数中返回错误信息。

`AgoraRtmTopicOption` 数据类型包含以下属性：

| 属性    |         类型          | 必填 | 默认值 | 描述                    |
| ------ | ----- | ------ | ---- | ----------------- |
| `users` | `[String]` |   选填   |   -    | 需要取消订阅的消息发布者（Publisher）的 `UserId` 列表，如果不设置，则默认随机取消订阅不超过 64 个用户。 |

### 基本用法 [#基本用法-3]

示例 1：取消订阅 Topic 中指定的消息发布者

```swift tab="async-await"
// async-await
let topic = "exampleTopic"
let topicOption = AgoraRtmTopicOption()
// Set specific users to unsubscribe from if needed
topicOption.users = ["user1", "user2"]
let (response, error) = await stChannel.unsubscribeTopic(topic, option: topicOption)
if let errorInfo = error {
    // Handle error
    print("Failed to unsubscribe from topic with error: \(errorInfo.reason)")
} else if let unsubscribeResponse = response {
    // Handle success
    print("Successfully unsubscribed from topic with specified options.")
} else {
    // Handle unknown error
    print("Unknown error occurred while unsubscribing from the topic.")
}
```

```swift tab="callback"
// callback
let topic = "exampleTopic"
let topicOption = AgoraRtmTopicOption()
// Set specific users to unsubscribe from if needed
topicOption.users = ["user1", "user2"]

stChannel.unsubscribeTopic(topic, option: topicOption) { (response, error) in
    if let errorInfo = error {
        // Handle error
        print("Failed to unsubscribe from topic with error: \(errorInfo.reason)")
    } else if let unsubscribeResponse = response {
        // Handle success
        print("Successfully unsubscribed from topic with specified options.")
    } else {
        // Handle unknown error
        print("Unknown error occurred while unsubscribing from the topic.")
    }
}
```

示例 2：随机取消订阅 Topic 中的 64 个消息发布者

```swift tab="async-await"
// async-await
let topic = "exampleTopic"

// Unsubscribing without options
let (response, error) = await stChannel.unsubscribeTopic(topic, option: nil)
if let errorInfo = error {
    // Handle error
    print("Failed to unsubscribe from topic with error: \(errorInfo.reason)")
} else if let unsubscribeResponse = response {
    // Handle success
    print("Successfully unsubscribed from topic.")
} else {
    // Handle unknown error
    print("Unknown error occurred while unsubscribing from the topic.")
}
```

```swift tab="callback"
// callback
let topic = "exampleTopic"

// Unsubscribing without options
stChannel.unsubscribeTopic(topic, option: nil) { (response, error) in
    if let errorInfo = error {
        // Handle error
        print("Failed to unsubscribe from topic with error: \(errorInfo.reason)")
    } else if let unsubscribeResponse = response {
        // Handle success
        print("Successfully unsubscribed from topic.")
    } else {
        // Handle unknown error
        print("Unknown error occurred while unsubscribing from the topic.")
    }
}
```
