You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中使用PubNub订阅带用户在线状态的频道并实现上下线实时监听

PubNub 在线状态自动回调实现方案

现有代码问题

你已经开启了通道的presence订阅,但是创建的SubscriptionListener没有绑定到PubNub实例,同时作为局部变量会在方法执行结束后被释放,所以无法收到自动触发的上下线事件回调,才需要手动调用hereNow查询状态。

修复实现要点

  • 将SubscriptionListener声明为类的成员属性,避免局部作用域回收
  • 调用pubnub.add(listener)将监听器绑定到PubNub实例,触发回调生效
  • 仅首次进入房间时调用hereNow拉取全量在线用户,后续上下线变动通过presenceChanged回调自动更新,无需重复手动查询

修复后参考代码

// 声明为类成员属性,避免被提前释放
private var presenceListener: SubscriptionListener?

func registerForConnectRoom(roomId: String) {
    let channelId = "ch:callroom:" + roomId
    pubnub.subscribe(to: [channelId], withPresence: true)
   
    presenceListener = SubscriptionListener()
    presenceListener?.didReceiveSubscription = { [weak self] event in
        switch event {
        case let .messageReceived(message):
            print("收到消息: \(message)")
        case let .connectionStatusChanged(status):
            print("连接状态变更: \(status)")
        case let .presenceChanged(presence):
            // 这里会自动触发上下线事件,不需要手动调用hereNow
            print("Presence事件触发: \(presence)")
            // 从presence对象直接获取变动用户和当前在线信息
            switch presence.event {
            case .join:
                print("\(presence.uuid ?? "未知用户") 进入房间")
                // 直接更新你的在线用户列表
            case .leave:
                print("\(presence.uuid ?? "未知用户") 主动离开房间")
            case .timeout:
                print("\(presence.uuid ?? "未知用户") 掉线离开房间")
            default:
                break
            }
            // 直接获取当前通道在线人数
            print("当前房间在线人数: \(presence.occupancy)")
        case let .subscribeError(error):
            print("订阅出错: \(error)")
        default:
            break
        }
    }
    // 核心步骤:将监听器绑定到PubNub实例才会收到回调
    if let listener = presenceListener {
        pubnub.add(listener)
    }
    
    // 仅首次进入房间时调用一次hereNow拉取初始全量在线用户
    hereNow(roomId: roomId)
}

func hereNow(roomId: String) {
    let channelId = "ch:callroom:" + roomId
    pubnub.hereNow(on: [channelId], includeState: true) { result in
        switch result {
        case let .success(presenceByChannel):
            if let myChannelPresence = presenceByChannel[channelId] {
                print("房间初始在线人数: \(myChannelPresence.occupancy)")
                print("房间初始在线用户列表: \(myChannelPresence.occupants)")
                // 这里初始化你的在线用户列表即可
            }
        case let .failure(error):
            print("拉取初始在线列表失败: \(error.localizedDescription)")
        }
    }
}

// 页面销毁时移除监听器、取消订阅避免内存泄漏
deinit {
    if let listener = presenceListener {
        pubnub.remove(listener)
    }
    pubnub.unsubscribeAll()
}

补充说明

presence事件会在用户加入、主动离开、掉线超过心跳超时时间时自动触发,无需轮询调用hereNow,能完全满足你需要的自动上下线回调需求。

内容的提问来源于stack exchange,提问作者user10469417

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 05:15:04