BarrageStore module from the AtomicXCore framework.
BarrageStore delivers a complete barrage solution for your live streaming app. Core features include:Core Concept | Type | Core Responsibility & Description |
struct | Represents the data model for a single barrage message. Contains all essential information such as sender (sender), message content (textContent or data), message type (messageType), and more. | |
struct | Represents the current state of the barrage module. The main property, messageList, is an array of [Barrage] storing all barrage messages in chronological order for the current live room. This serves as the data source for UI rendering. | |
class | The core management class for barrage functionality. Use it to send messages (sendTextMessage, sendCustomMessage), and subscribe to its state property to receive all barrage message updates. |
BarrageStore instance bound to the current live room's liveId, and set up a subscriber to receive the latest complete barrage message list in real time.import Foundationimport AtomicXCore // Import the core libraryimport Combine // For reactive programmingclass BarrageManager {private let liveId: Stringprivate let barrageStore: BarrageStoreprivate var cancellables = Set<AnyCancellable>()// Publisher for the complete message list, for UI layer subscriptionlet messagesPublisher = PassthroughSubject<[Barrage], Never>()init(liveId: String) {self.liveId = liveId// 1. Obtain the BarrageStore singleton for the given liveIdself.barrageStore = BarrageStore.create(liveID: liveId)// 2. Start listening for barrage messages immediately after initializationsubscribeToBarrageUpdates()}private func subscribeToBarrageUpdates() {barrageStore.state.subscribe() // Subscribe to all BarrageState changes.receive(on: DispatchQueue.main) // Ensure main thread for UI safety.sink { [weak self] barrageState in// 3. Forward the updated message list to the UI layer// Note: This provides the complete list, including all historical messagesself?.messagesPublisher.send(barrageState.messageList)}.store(in: &cancellables) // Manage subscription lifecycle}
sendTextMessage method to broadcast a plain text message to all users in the live room.extension BarrageManager {/// Send a text barrage messagefunc sendTextMessage(text: String) {// Prevent sending empty messagesguard !text.isEmpty else {print("Barrage content cannot be empty")return}// Send the message using the core APIbarrageStore.sendTextMessage(text: text, extensionInfo: nil) { result in// Handle the result in the callback, e.g., show a prompt to the userswitch result {case .success:print("Text barrage '\\(text)' sent successfully")case .failure(let error):print("Failed to send text barrage: \\(error.localizedDescription)")}}}}
Parameter | Type | Description |
text | String | The text content to send. |
extensionInfo | [String: String]? | Additional extension information for business customization. |
completion | CompletionClosure? | Callback after sending is complete, containing the success or failure result. |
businessId and data.extension BarrageManager {/// Send a custom barrage, e.g., for sending giftsfunc sendGiftMessage(giftId: String, giftCount: Int) {// 1. Define a business-recognizable IDlet businessId = "live_gift"// 2. Encode business data as a JSON stringlet giftData: [String: Any] = ["gift_id": giftId, "gift_count": giftCount]guard let jsonData = try? JSONSerialization.data(withJSONObject: giftData),let jsonString = String(data: jsonData, encoding: .utf8) else {print("Failed to encode gift data as JSON")return}// 3. Send the custom message using the core APIbarrageStore.sendCustomMessage(businessID: businessId, data: jsonString) { result inswitch result {case .success:print("Gift message (custom barrage) sent successfully")case .failure(let error):print("Failed to send gift message: \\(error.localizedDescription)")}}}}
Parameter | Type | Description |
businessId | String | Unique business identifier, e.g., "live_gift", used by the receiver to distinguish different custom messages. |
data | String | Business data, usually a JSON-formatted string. |
completion | CompletionClosure? | Callback after sending is complete. |
extension BarrageManager {/// Insert a welcome tip into the local message listfunc showWelcomeMessage(for user: LiveUserInfo) {// 1. Create a Barrage messagevar welcomeTip = Barrage()welcomeTip.messageType = .text // Reuse the text type for displaywelcomeTip.textContent = "Welcome \\(user.userName) to the live room!"// sender can be left empty or set to a system user identifier// 2. Insert the message into the local listbarrageStore.appendLocalTip(message: welcomeTip)}}
Parameter | Type | Description |
message | Barrage | The message object to insert locally. The SDK appends this message to the messageList in BarrageState. |
disableSendMessage method in LiveAudienceStore to mute or unmute a user. This state persists even if the user rejoins the live room.import AtomicXCore// 1. Get the LiveAudienceStore instance for the current live roomlet audienceStore = LiveAudienceStore.create(liveID: "your_live_id")// 2. Specify the user ID and mute statuslet userIdToMute = "user_id_to_be_muted"let shouldDisable = true // true to mute, false to unmute// 3. Call the API to perform the operationaudienceStore.disableSendMessage(userID: userIdToMute, isDisable: shouldDisable) { [weak self] result inguard let self = self else { return }switch result {case .success:print("\\(shouldDisable ? "Muted" : "Unmuted") user \\(userIdToMute) successfully")case .failure(let error):print("Operation failed: \\(error.localizedDescription)")}}
LiveListStore.import AtomicXCore// 1. Get the LiveListStore singletonlet liveListStore = LiveListStore.shared// 2. Get the current live room info and modify the global mute statusvar currentLiveInfo = liveListStore.state.value.currentLivecurrentLiveInfo.isMessageDisable = true // true to enable global mute, false to disable// 3. Call the update API and specify the modify flagliveListStore.updateLiveInfo(currentLiveInfo, modifyFlag: .isMessageDisable) { result inswitch result {case .success:print("Global mute status updated successfully")case .failure(let error):print("Operation failed: \\(error.localizedDescription)")}}
BarrageStore, use the following strategies to ensure smooth and stable user experiences in high-concurrency live streaming scenarios. This section provides optimization strategies and code samples for three core business scenarios.tableView.reloadData() on every update, the main thread will be blocked by intensive UI layout and rendering, causing UI lag.reloadData() calls per second to just 3-4, greatly improving smoothness.BarrageUIManager class with an internal buffer and timer to batch update data to the UITableView.class BarrageUIManager {private var latestMessageList: [BarrageViewModel]?private var refreshTimer: Timer?private weak var tableView: UITableView?private var dataSource: [BarrageViewModel] = []init(tableView: UITableView) {self.tableView = tableView// Check every 0.3 seconds if a refresh is neededself.refreshTimer = Timer.scheduledTimer(withTimeInterval: 0.3, repeats: true) { [weak self] _ inself?.refreshUIIfNeeded()}}/// Frequently called from outside, passing in the latest full listfunc update(with fullList: [BarrageViewModel]) {self.latestMessageList = fullList}private func refreshUIIfNeeded() {// Check if there is new data to refreshguard let newList = self.latestMessageList, let tableView = self.tableView else { return }self.latestMessageList = nil // Clear the flag to avoid repeated refreshes// Update the data source and refresh the UIself.dataSource = newListtableView.reloadData()}deinit {refreshTimer?.invalidate()}}
messageList that grows indefinitely during long live streams. Even if the UI layer throttles updates, the data layer's large array will continue to consume memory, eventually causing the app to crash.class BarrageUIManager {private let capacity: Int = 500 // Retain only the latest 500 messages// ... (other code as above) ...private func refreshUIIfNeeded() {guard let fullList = self.latestMessageList, let tableView = self.tableView else { return }self.latestMessageList = nil// Only keep the latest N messageslet cappedList = Array(fullList.suffix(self.capacity))self.dataSource = cappedListtableView.reloadData()}}
UITableViewCell, enable the layer's drawsAsynchronously property to allow the system to perform drawing tasks on a background thread.import UIKit// In your custom barrage cellclass BarrageCell: UITableViewCell {// ... (UILabel, UIImageView, and other subview declarations)override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {super.init(style: style, reuseIdentifier: reuseIdentifier)// Enable asynchronous drawingself.layer.drawsAsynchronously = true}required init?(coder: NSCoder) {fatalError("init(coder:) has not been implemented")}func configure(with viewModel: BarrageViewModel) {// Set label text, images, etc.// With asynchronous drawing enabled, rendering occurs on a background thread when possible}// Advanced: fully manual drawingoverride func draw(_ rect: CGRect) {// For finer control, manually draw text and images here using Core Graphics// Combine generating UIImage on a background thread, then draw it in the main thread's draw method for fully asynchronous rendering}}
sendCustomMessage. { "type": "colored_text", "text": "This is a colored bullet comment!", "color": "#FF5733" }
data parameter of sendCustomMessage. The businessID can be set to a unique identifier for your use case, such as barrage_style_v1.BarrageType.CUSTOM and whether the businessID matches. If so, parse the data string (usually as JSON), and render your custom UI style based on the parsed data (such as color, text).BarrageStore instance for that live room. You do not need to manage singletons manually.sendTextMessage method provides a completion callback. Check whether the callback indicates success or failure. If it fails, the error message will indicate the problem (such as "You have been muted," "Network error," etc.).barrageStore.barrageState.messageList after the live session for the corresponding liveID has started. If you start listening before joining the live room, you may miss some messages.Feedback