Skip to main content
Events allow different parts of your app to communicate without direct dependencies. When a user performs an action (like blocking someone, deleting a conversation, or sending a message), events are emitted so other components can react accordingly.

How Events Work

  1. Subscribe to events using addListener in viewDidLoad
  2. React to events in your listener callback methods
  3. Unsubscribe using removeListener in viewWillDisappear
import UIKit
import CometChatUIKitSwift
import CometChatSDK

class MyViewController: UIViewController {
    
    private let listenerId = "my-unique-listener"
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Subscribe to events
        CometChatUserEvents.addListener(listenerId, self)
        CometChatGroupEvents.addListener(listenerId, self)
        CometChatConversationEvents.addListener(listenerId, self)
        CometChatMessageEvents.addListener(listenerId, self)
        CometChatCallEvents.addListener(listenerId, self)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        // Unsubscribe to prevent memory leaks
        CometChatUserEvents.removeListener(listenerId)
        CometChatGroupEvents.removeListener(listenerId)
        CometChatConversationEvents.removeListener(listenerId)
        CometChatMessageEvents.removeListener(listenerId)
        CometChatCallEvents.removeListener(listenerId)
    }
}

User Events

Listen for user-related actions like blocking and unblocking.
import UIKit
import CometChatUIKitSwift
import CometChatSDK

class UserEventsViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        CometChatUserEvents.addListener("user-listener", self)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        CometChatUserEvents.removeListener("user-listener")
    }
}

extension UserEventsViewController: CometChatUserEventListener {
    
    func onUserBlock(user: User) {
        print("Blocked: \(user.name ?? "")")
        // Update UI - hide user from lists, disable messaging
    }
    
    func onUserUnblock(user: User) {
        print("Unblocked: \(user.name ?? "")")
        // Update UI - show user in lists, enable messaging
    }
}

Emit User Events

Notify other components when you block/unblock a user:
// After blocking a user
CometChatUserEvents.emitOnUserBlock(user: blockedUser)

// After unblocking a user
CometChatUserEvents.emitOnUserUnblock(user: unblockedUser)

User Events Reference

EventDescription
onUserBlockUser was blocked by logged-in user
onUserUnblockUser was unblocked by logged-in user

Group Events

Listen for group-related actions like creating groups, adding members, and role changes.
import UIKit
import CometChatUIKitSwift
import CometChatSDK

class GroupEventsViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        CometChatGroupEvents.addListener("group-listener", self)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        CometChatGroupEvents.removeListener("group-listener")
    }
}

extension GroupEventsViewController: CometChatGroupEventListener {
    
    // Group lifecycle
    func onGroupCreate(group: Group) {
        print("Group created: \(group.name ?? "")")
    }
    
    func onGroupDelete(group: Group) {
        print("Group deleted: \(group.name ?? "")")
    }
    
    func onCreateGroupClick() {
        print("Create group button tapped")
    }
    
    // Member join/leave
    func onGroupMemberJoin(joinedUser: User, joinedGroup: Group) {
        print("\(joinedUser.name ?? "") joined \(joinedGroup.name ?? "")")
    }
    
    func onGroupMemberLeave(leftUser: User, leftGroup: Group) {
        print("\(leftUser.name ?? "") left \(leftGroup.name ?? "")")
    }
    
    func onGroupMemberAdd(group: Group, members: [GroupMember], addedBy: User) {
        print("\(members.count) members added to \(group.name ?? "")")
    }
    
    // Moderation
    func onGroupMemberKick(kickedUser: User, kickedGroup: Group) {
        print("\(kickedUser.name ?? "") kicked from \(kickedGroup.name ?? "")")
    }
    
    func onGroupMemberBan(bannedUser: User, bannedGroup: Group) {
        print("\(bannedUser.name ?? "") banned from \(bannedGroup.name ?? "")")
    }
    
    func onGroupMemberUnban(unbannedUserUser: User, unbannedUserGroup: Group) {
        print("\(unbannedUserUser.name ?? "") unbanned")
    }
    
    // Role changes
    func onGroupMemberChangeScope(updatedBy: User, updatedUser: User, scopeChangedTo: CometChat.MemberScope, scopeChangedFrom: CometChat.MemberScope, group: Group) {
        print("\(updatedUser.name ?? "") role: \(scopeChangedFrom)\(scopeChangedTo)")
    }
    
    func onOwnershipChange(group: Group?, member: GroupMember?) {
        print("Ownership transferred to \(member?.name ?? "")")
    }
}

Emit Group Events

Notify other components about group actions:
// Group created
CometChatGroupEvents.emitOnGroupCreate(group: newGroup)

// Group deleted
CometChatGroupEvents.emitOnGroupDelete(group: deletedGroup)

// Member joined
CometChatGroupEvents.emitOnGroupMemberJoin(joinedUser: user, joinedGroup: group)

// Member left
CometChatGroupEvents.emitOnGroupMemberLeave(leftUser: user, leftGroup: group)

// Members added
CometChatGroupEvents.emitOnGroupMemberAdd(group: group, members: newMembers, addedBy: currentUser)

// Member kicked
CometChatGroupEvents.emitOnGroupMemberKick(kickedUser: user, kickedGroup: group, kickedBy: admin)

// Member banned
CometChatGroupEvents.emitOnGroupMemberBan(bannedUser: user, bannedGroup: group, bannedBy: admin)

// Member unbanned
CometChatGroupEvents.emitOnGroupMemberUnban(unbannedUserUser: user, unbannedUserGroup: group, unbannedBy: admin)

// Role changed
CometChatGroupEvents.emitOnGroupMemberChangeScope(
    updatedBy: admin,
    updatedUser: member,
    scopeChangedTo: .admin,
    scopeChangedFrom: .participant,
    group: group
)

Group Events Reference

EventDescription
onGroupCreateNew group created
onGroupDeleteGroup deleted
onCreateGroupClickCreate group button tapped
onGroupMemberJoinUser joined a group
onGroupMemberLeaveUser left a group
onGroupMemberAddMembers added to group
onGroupMemberKickMember kicked from group
onGroupMemberBanMember banned from group
onGroupMemberUnbanMember unbanned
onGroupMemberChangeScopeMember role changed
onOwnershipChangeGroup ownership transferred

Conversation Events

Listen for conversation-level actions like delete and update.
import UIKit
import CometChatUIKitSwift
import CometChatSDK

class ConversationEventsViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        CometChatConversationEvents.addListener("conversation-listener", self)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        CometChatConversationEvents.removeListener("conversation-listener")
    }
}

extension ConversationEventsViewController: CometChatConversationEventListener {
    
    func ccConversationDeleted(conversation: Conversation) {
        print("Conversation deleted: \(conversation.conversationId ?? "")")
        // Remove from local list, update UI
    }
    
    func ccUpdateConversation(conversation: Conversation) {
        print("Conversation updated: \(conversation.conversationId ?? "")")
        // Refresh conversation data in UI
    }
}

Emit Conversation Events

// Conversation deleted
CometChatConversationEvents.ccConversationDelete(conversation: deletedConversation)

// Conversation updated
CometChatConversationEvents.ccUpdateConversation(conversation: updatedConversation)

Conversation Events Reference

EventDescription
ccConversationDeletedConversation was deleted
ccUpdateConversationConversation was updated

Message Events

Listen for message-related actions like send, edit, delete, and reactions.
import UIKit
import CometChatUIKitSwift
import CometChatSDK

class MessageEventsViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        CometChatMessageEvents.addListener("message-listener", self)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        CometChatMessageEvents.removeListener("message-listener")
    }
}

extension MessageEventsViewController: CometChatMessageEventListener {
    
    // Message lifecycle
    func onMessageSent(message: BaseMessage, status: MessageStatus) {
        switch status {
        case .inProgress:
            print("Sending...")
        case .success:
            print("Message sent: \(message.id)")
        case .error:
            print("Send failed")
        @unknown default:
            break
        }
    }
    
    func onMessageEdit(message: BaseMessage, status: MessageStatus) {
        print("Message edited: \(message.id)")
    }
    
    func onMessageDelete(message: BaseMessage, status: MessageStatus) {
        print("Message deleted: \(message.id)")
    }
    
    func onMessageRead(message: BaseMessage) {
        print("Message read: \(message.id)")
    }
    
    func onMessageReply(message: BaseMessage, status: MessageStatus) {
        print("Reply sent to: \(message.id)")
    }
    
    // Reactions
    func onMessageReact(message: BaseMessage, reaction: CometChatMessageReaction) {
        print("Reaction: \(reaction.reaction ?? "")")
    }
    
    func onLiveReaction(reaction: TransientMessage) {
        print("Live reaction received")
    }
    
    // Thread updates
    func onParentMessageUpdate(message: BaseMessage) {
        print("Thread parent updated: \(message.id)")
    }
    
    // Navigation
    func onViewInformation(user: User) {
        print("View user info: \(user.name ?? "")")
    }
    
    func onViewInformation(group: Group) {
        print("View group info: \(group.name ?? "")")
    }
    
    // Calls from message screen
    func onVoiceCall(user: User) {
        print("Voice call to: \(user.name ?? "")")
    }
    
    func onVideoCall(user: User) {
        print("Video call to: \(user.name ?? "")")
    }
    
    func onVoiceCall(group: Group) {
        print("Group voice call: \(group.name ?? "")")
    }
    
    func onVideoCall(group: Group) {
        print("Group video call: \(group.name ?? "")")
    }
    
    // Errors
    func onMessageError(error: CometChatException) {
        print("Error: \(error.errorDescription)")
    }
}

Emit Message Events

// Message sent (with status)
CometChatMessageEvents.emitOnMessageSent(message: sentMessage, status: .success)

// Message edited
CometChatMessageEvents.emitOnMessageEdit(message: editedMessage, status: .success)

// Message deleted
CometChatMessageEvents.emitOnMessageDelete(message: deletedMessage)

// Message read
CometChatMessageEvents.emitOnMessageRead(message: readMessage)

// Live reaction
CometChatMessageEvents.emitOnLiveReaction(reaction: transientMessage)

// View user/group info
CometChatMessageEvents.emitOnViewInformation(user: selectedUser)

// Thread parent updated
CometChatMessageEvents.emitOnParentMessageUpdate(message: parentMessage)

Message Events Reference

EventDescription
onMessageSentMessage sent (inProgress, success, or error)
onMessageEditMessage edited
onMessageDeleteMessage deleted
onMessageReadMessage marked as read
onMessageReplyReply sent to a message
onMessageReactReaction added to message
onLiveReactionLive reaction sent
onParentMessageUpdateThread parent message updated
onViewInformationInfo button tapped (user or group)
onVoiceCallVoice call initiated
onVideoCallVideo call initiated
onMessageErrorMessage operation failed

Call Events

Listen for call-related actions like initiating, accepting, and ending calls.
import UIKit
import CometChatUIKitSwift
import CometChatSDK

class CallEventsViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        CometChatCallEvents.addListener("call-listener", self)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        CometChatCallEvents.removeListener("call-listener")
    }
}

extension CallEventsViewController: CometChatCallEventListener {
    
    // Outgoing calls
    func onCallInitiated(call: Call) {
        print("Calling: \(call.receiverUid)")
    }
    
    func onOutgoingCallAccepted(call: Call) {
        print("Call accepted by recipient")
    }
    
    func onOutgoingCallRejected(call: Call) {
        print("Call rejected by recipient")
    }
    
    // Incoming calls
    func onIncomingCallAccepted(call: Call) {
        print("You accepted the call")
    }
    
    func onIncomingCallRejected(call: Call) {
        print("You rejected the call")
    }
    
    // Call ended
    func onCallEnded(call: Call) {
        print("Call ended")
    }
}

Emit Call Events

// Call initiated
CometChatCallEvents.emitOnCallInitiated(call: outgoingCall)

// Call ended
CometChatCallEvents.emitOnCallEnded(call: endedCall)

// Incoming call accepted
CometChatCallEvents.emitOnIncomingCallAccepted(call: acceptedCall)

// Incoming call rejected
CometChatCallEvents.emitOnIncomingCallRejected(call: rejectedCall)

// Outgoing call accepted
CometChatCallEvents.emitOnOutgoingCallAccepted(call: acceptedCall)

// Outgoing call rejected
CometChatCallEvents.emitOnOutgoingCallRejected(call: rejectedCall)

Call Events Reference

EventDescription
onCallInitiatedOutgoing call started
onOutgoingCallAcceptedRecipient accepted the call
onOutgoingCallRejectedRecipient rejected the call
onIncomingCallAcceptedYou accepted an incoming call
onIncomingCallRejectedYou rejected an incoming call
onCallEndedCall ended (any reason)

Complete Example: App-Wide Event Manager

Create a centralized event manager to handle events across your entire app:
import UIKit
import CometChatUIKitSwift
import CometChatSDK

// MARK: - Singleton Event Manager
class ChatEventManager {
    
    static let shared = ChatEventManager()
    private let listenerId = "app-event-manager"
    
    private init() {}
    
    func startListening() {
        CometChatUserEvents.addListener(listenerId, self)
        CometChatGroupEvents.addListener(listenerId, self)
        CometChatConversationEvents.addListener(listenerId, self)
        CometChatMessageEvents.addListener(listenerId, self)
        CometChatCallEvents.addListener(listenerId, self)
    }
    
    func stopListening() {
        CometChatUserEvents.removeListener(listenerId)
        CometChatGroupEvents.removeListener(listenerId)
        CometChatConversationEvents.removeListener(listenerId)
        CometChatMessageEvents.removeListener(listenerId)
        CometChatCallEvents.removeListener(listenerId)
    }
}

// MARK: - User Events
extension ChatEventManager: CometChatUserEventListener {
    func onUserBlock(user: User) {
        NotificationCenter.default.post(name: .userBlocked, object: user)
    }
    
    func onUserUnblock(user: User) {
        NotificationCenter.default.post(name: .userUnblocked, object: user)
    }
}

// MARK: - Group Events
extension ChatEventManager: CometChatGroupEventListener {
    func onGroupCreate(group: Group) {
        NotificationCenter.default.post(name: .groupCreated, object: group)
    }
    
    func onGroupDelete(group: Group) {
        NotificationCenter.default.post(name: .groupDeleted, object: group)
    }
    
    func onGroupMemberJoin(joinedUser: User, joinedGroup: Group) {
        NotificationCenter.default.post(name: .memberJoined, object: nil, 
            userInfo: ["user": joinedUser, "group": joinedGroup])
    }
    
    func onGroupMemberLeave(leftUser: User, leftGroup: Group) {
        NotificationCenter.default.post(name: .memberLeft, object: nil,
            userInfo: ["user": leftUser, "group": leftGroup])
    }
    
    // Implement other required methods...
    func onGroupMemberAdd(group: Group, members: [GroupMember], addedBy: User) {}
    func onGroupMemberKick(kickedUser: User, kickedGroup: Group) {}
    func onGroupMemberBan(bannedUser: User, bannedGroup: Group) {}
    func onGroupMemberUnban(unbannedUserUser: User, unbannedUserGroup: Group) {}
    func onGroupMemberChangeScope(updatedBy: User, updatedUser: User, scopeChangedTo: CometChat.MemberScope, scopeChangedFrom: CometChat.MemberScope, group: Group) {}
    func onOwnershipChange(group: Group?, member: GroupMember?) {}
    func onCreateGroupClick() {}
}

// MARK: - Conversation Events
extension ChatEventManager: CometChatConversationEventListener {
    func ccConversationDeleted(conversation: Conversation) {
        NotificationCenter.default.post(name: .conversationDeleted, object: conversation)
    }
    
    func ccUpdateConversation(conversation: Conversation) {
        NotificationCenter.default.post(name: .conversationUpdated, object: conversation)
    }
}

// MARK: - Message Events
extension ChatEventManager: CometChatMessageEventListener {
    func onMessageSent(message: BaseMessage, status: MessageStatus) {
        if status == .success {
            NotificationCenter.default.post(name: .messageSent, object: message)
        }
    }
    
    // Implement other required methods...
    func onMessageEdit(message: BaseMessage, status: MessageStatus) {}
    func onMessageDelete(message: BaseMessage, status: MessageStatus) {}
    func onMessageRead(message: BaseMessage) {}
    func onLiveReaction(reaction: TransientMessage) {}
    func onMessageReact(message: BaseMessage, reaction: CometChatMessageReaction) {}
    func onParentMessageUpdate(message: BaseMessage) {}
    func onViewInformation(user: User) {}
    func onViewInformation(group: Group) {}
    func onVoiceCall(user: User) {}
    func onVideoCall(user: User) {}
    func onVoiceCall(group: Group) {}
    func onVideoCall(group: Group) {}
    func onMessageError(error: CometChatException) {}
    func onMessageReply(message: BaseMessage, status: MessageStatus) {}
}

// MARK: - Call Events
extension ChatEventManager: CometChatCallEventListener {
    func onCallInitiated(call: Call) {
        NotificationCenter.default.post(name: .callStarted, object: call)
    }
    
    func onCallEnded(call: Call) {
        NotificationCenter.default.post(name: .callEnded, object: call)
    }
    
    func onIncomingCallAccepted(call: Call) {}
    func onIncomingCallRejected(call: Call) {}
    func onOutgoingCallAccepted(call: Call) {}
    func onOutgoingCallRejected(call: Call) {}
}

// MARK: - Notification Names
extension Notification.Name {
    static let userBlocked = Notification.Name("userBlocked")
    static let userUnblocked = Notification.Name("userUnblocked")
    static let groupCreated = Notification.Name("groupCreated")
    static let groupDeleted = Notification.Name("groupDeleted")
    static let memberJoined = Notification.Name("memberJoined")
    static let memberLeft = Notification.Name("memberLeft")
    static let conversationDeleted = Notification.Name("conversationDeleted")
    static let conversationUpdated = Notification.Name("conversationUpdated")
    static let messageSent = Notification.Name("messageSent")
    static let callStarted = Notification.Name("callStarted")
    static let callEnded = Notification.Name("callEnded")
}

Using the Event Manager

// AppDelegate.swift
class AppDelegate: UIResponder, UIApplicationDelegate {
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        // Start listening for events app-wide
        ChatEventManager.shared.startListening()
        
        return true
    }
}

// Any ViewController
class MyViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Listen for specific events via NotificationCenter
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(handleUserBlocked),
            name: .userBlocked,
            object: nil
        )
    }
    
    @objc private func handleUserBlocked(_ notification: Notification) {
        guard let user = notification.object as? User else { return }
        print("User blocked: \(user.name ?? "")")
        // Update your UI
    }
    
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
}

Best Practices

  1. Always remove listeners - Call removeListener in viewWillDisappear to prevent memory leaks
  2. Use unique listener IDs - Avoid conflicts between components by using descriptive, unique IDs
  3. Update UI on main thread - Dispatch UI updates to the main thread when handling events
  4. Don’t emit unnecessarily - Only emit events when state actually changes
  5. Use a central manager - For app-wide event handling, create a singleton manager

Troubleshooting

IssueSolution
Events not firingVerify listener is added before the action occurs
Duplicate eventsCheck you’re not adding the same listener multiple times
Memory leaksEnsure removeListener is called in viewWillDisappear
UI not updatingDispatch UI updates to main thread with DispatchQueue.main.async
Listener ID conflictsUse unique, descriptive IDs for each listener