从Socket接收批量数据时,应用冻结。iOS | Socket.io | 领域快速

Pee*_*wal 6 sockets chat realm ios

我正在开发一个聊天应用程序,每次可以收到许多消息,导致应用程序冻结。以下是我的套接字接收器:

func receiveNewDirectMessages() {
    self.socket?.on(EventListnerKeys.message.rawValue, callback: { (arrAckData, ack) in
        print_debug(arrAckData)
        guard let dictMsg = arrAckData.first as? JSONDictionary else { return }
        guard let data = dictMsg[ApiKey.data] as? JSONDictionary else { return }
        guard let chatData = data[ApiKey.data] as? JSONDictionary else { return }
        guard let messageId = chatData[ApiKey._id]  as? String , let chatId = chatData[ApiKey.chatId] as? String else { return }
        if MessageModel.getMessageModel(msgId: messageId) != nil { return }
        let isChatScreen = self.isChatScreen
        let localMsgId = "\(arc4random())\(Date().timeIntervalSince1970)"
        if let senderInfo = data[ApiKey.senderInfo] as? JSONDictionary, let userId = senderInfo[ApiKey.userId] as? String, userId != User.getUserId() {
            _ = AppUser.writeAppUserModelWith(userData: senderInfo)
        }
        let msgModel = MessageModel.saveMessageData(msgData: chatData, localMsgId: localMsgId, msgStatus: 2, seenByMe: false)
        let chatModel = ChatModel.saveInboxData(localChatId: msgModel.localChatId, inboxData: chatData)
        if isChatScreen {
            self.emitMessageStatus(msgId: messageId, chatId: chatId, socketService: .messageStatus, status: .delivered)
            self.emitMessageStatus(msgId: messageId, chatId: chatId, socketService: .messageStatus, status: .seen)
        } else {
            ChatModel.updateUnreadCount(localChatId: chatModel.localChatId, incrementBy: 1)
            self.emitMessageStatus(msgId: messageId, chatId: chatId, socketService: .messageStatus, status: .delivered)
        }
        TabController.shared.updateChatBadgeCount()
    })
}
Run Code Online (Sandbox Code Playgroud)

上面发生的事情:1.我正在此套接字侦听器中一对一接收所有未传递的消息。2.提取消息数据3.将收到的发件人信息保存到Realm DB 4.将消息模型保存到realm DB 5.在领域DB中保存/更新聊天线程6.发出对收到消息的确认7.更新聊天徽章计数标签栏

以下是我确认消息传递的发射器。

 func emitMessageStatus(msgId: String, chatId: String, socketService: SocketService, status: MessageStatusAction) {

    // Create Message data packet to be sent to socket server
    var msgDataPacket = [String: Any]()
    msgDataPacket[ApiKey.type] = socketService.type
    msgDataPacket[ApiKey.actionType] = socketService.listenerType
    msgDataPacket[ApiKey.data] = [
        ApiKey.messageId: msgId,
        ApiKey.chatId: chatId,
        ApiKey.userId: User.getUserId(),
        ApiKey.statusAction: status.rawValue
    ]
    // send the messsage  data packet to socket server & wait for the acknowledgement
    self.emit(with: EventListnerKeys.socketService.rawValue, msgDataPacket) { (arrAckData) in
        print_debug(arrAckData)
        guard let dictMsg = arrAckData.first as? JSONDictionary else { return }
        if let msgData = dictMsg[ApiKey.data] as? [String: Any] {
            // Update delivered Seen Status here
            if let msgId = msgData[ApiKey.messageId] as? String, let actionType = msgData[ApiKey.statusAction] as? String, let msgStatusAction = MessageStatusAction(rawValue: actionType) {
                switch msgStatusAction {
                case .delivered:
                    if let deliveredTo = msgData[ApiKey.deliveredTo] as? [[String: Any]] {
                        _ = MessageModel.updateMsgDelivery(msgId: msgId, deliveredTo: deliveredTo)
                    }
                case .seen:
                    if let seenBy = msgData[ApiKey.seenBy] as? [[String: Any]] {
                        _ = MessageModel.updateMsgSeen(msgId: msgId, seenBy: seenBy)
                    }
                case .pin:
                    MessageModel.clearPinnedMessages(chatId: chatId)
                    if let pinTime = msgData[ApiKey.pinTime] as? Double {
                        MessageModel.updatePinnedStatus(msgId: msgId, isPinned: true, pinTime: pinTime)
                    }
                case .unPin:
                    if let pinTime = msgData[ApiKey.pinTime] as? Double {
                        MessageModel.updatePinnedStatus(msgId: msgId, isPinned: false, pinTime: pinTime)
                    }
                case .delete:
                    MessageModel.deleteMessage(msgId: msgId)
                case .ackMsgStatus, .like, .unlike:
                    break
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

上面发生了什么:

  1. 封装所有相关信息以确认事件
  2. 确认交付后更新领域数据库

现在,我无法在这里挑战完美的线程策略。在后台线程中写什么,我应该在主线程中写什么。但是我尝试这样做,但这会导致随机崩溃或数据包丢失。

任何人都可以引导我就这个话题提出建议。我将非常感谢。

tul*_*dev 2

  1. 尝试使用后台线程进行数据处理/非 UI 处理。
  2. 减少更新UI次数

    使用 debounce 之类的方式代替处理 1 by 1 消息。您可以存储新消息,然后用n条新消息更新UI。因此,您可以为 100 条消息执行 1 次,而不是为 100 条消息更新 UI/将数据保存到数据库 100 次。更详细:对于每条新消息,将其添加到数组中。呼叫防抖器。Debouncer 会延迟一个函数调用,每次调用它时,它都会延迟前面的调用,直到延迟时间结束。因此,例如200毫秒后,如果没有新消息,将调用更新函数(去抖处理的回调函数)。然后用 n 个新存储的消息更新 ui/db。

    您可以按时间对消息进行分组,例如按 1 小时分组。然后在每个时间组之间进行延迟更新。您可以在调用 debouncer 时执行此操作 -> 按时间对消息进行分组 -> 按每个组更新 db/ui。你可以使用setTimeout,比如更新组1,100ms后更新组2,这样ui就不会被冻结