SwiftUI - @Published 数组不更新 subview

标签 swiftui

这是我的模型:

struct ChatRoom: Identifiable, Equatable {
    static func == (lhs: ChatRoom, rhs: ChatRoom) -> Bool {
        lhs.id == rhs.id
    }
    
    struct LastMessage: Codable {
        let isSeen: Bool
        var isOfCurrentUser: Bool?
        let createdAt: Date
        let senderId, text: String
    }
    
    let id: String
    let userIds: [String]
    var lastMessage: LastMessage
    let otherUser: User
    let currentUserAvatarObject: [String : Any]?
    let isTyping: Bool
    var blockerIds: [String]
    let archiverIds: [String]
    let messages: Int
    let senderMessages: Int
    let receiverMessages: Int
}

我有 ChatRoomsListView View ,它初始化其 ViewModel 如下:

struct ChatRoomsListView: View {
    @StateObject private var viewModel = ViewModel()
    
    var body: some View {
        ZStack {
            Color.black.ignoresSafeArea()
            
            VStack {
                HStack {
                    Button {
                    } label: {
                        Image(systemName: "camera")
                            .scaledToFit()
                            .foregroundColor(.white)
                            .frame(width: 30, height: 30)
                            .padding(6)
                            .background(
                                Circle().foregroundColor(.white.opacity(0.15))
                            )
                    }
                    
                    Spacer()
                    
                    Text("Chats")
                        .foregroundColor(.white)
                        .offset(x: -20)
                    
                    Spacer()
                }
                
                ScrollView(.vertical) {
                    LazyVStack {
                        ForEach(viewModel.chatRooms) { chatRoom in
                            ChatRoomView(chatRoom: chatRoom)
                        }
                    }
                }
            }.padding(.vertical, 44)
            
            if viewModel.chatRooms.isEmpty {
                Text("It seems you haven’t chatted with anyone yet! That’s ok!")
                    .foregroundColor(.white)
                    .multilineTextAlignment(.center)
                    .padding(.horizontal)
            }
        }
    }
}

private struct ChatRoomView: View {
    let chatRoom: ChatRoom
    
    private var text: String {
        chatRoom.isTyping ? NSLocalizedString("Typing...", comment: "") : chatRoom.lastMessage.text
    }
    
    private var hasUnseenMessage: Bool {
        !chatRoom.lastMessage.isSeen && chatRoom.lastMessage.isOfCurrentUser == false
    }
    
    var body: some View {
        ZStack {
            Color.black.ignoresSafeArea()
            
            VStack(spacing: 0) {
                HStack {
                    if hasUnseenMessage {
                        Circle()
                            .frame(width: 10, height: 10)
                            .foregroundColor(.blue)
                    }
                    
                    VStack(alignment: .leading) {
                        Text(chatRoom.otherUser.username)
                            .foregroundColor(.white)
                        
                        Text(text)
                            .foregroundColor(.white)
                            .lineLimit(1)
                    }
                    
                    Spacer()
                    
                    if chatRoom.lastMessage.isSeen && chatRoom.lastMessage.isOfCurrentUser == true {
                        Image(systemName: "checkmark.circle")
                            .foregroundColor(.white)
                    }
                }.padding()
            }
        }
    }
}

这是ViewModel:

extension ChatRoomsListView {
    class ViewModel: ObservableObject {
        @Published var chatRooms = [ChatRoom]()

    
    // -----------------------------
    
    @Injected private var chatRoomsService: ChatRoomsRepository
    @Injected private var currentUserService: CurrentUserRepository
    
    // -----------------------------
    
    init() {
        getChatRooms()
        subscribeToChatRoomUpdates()
    }
    
    private func getChatRooms() {
        guard let currentUser = currentUserService.user else { return }
        
        chatRoomsService.getChatRooms(currentUser: currentUser) { [weak self] chatRooms in
            self?.chatRooms = chatRooms
        }
    }
    
    private func subscribeToChatRoomUpdates() {
        guard let currentUser = currentUserService.user else { return }
        
        chatRoomsService.subscribeToChatRoomUpdates(currentUser: currentUser) { [weak self] chatRooms in
            DispatchQueue.main.async {
                for chatRoom in chatRooms {
                    if let index = self?.chatRooms.firstIndex(where: { $0.id == chatRoom.id }) {
                        self?.chatRooms[index] = chatRoom
                    } else {
                        self?.chatRooms.insert(chatRoom, at: 0)
                    }
                }
                
                self?.chatRooms.removeAll(where: { $0.archiverIds.contains(currentUser.id) })
                self?.chatRooms.sort(by: { $0.lastMessage.createdAt > $1.lastMessage.createdAt })
            }
        }
    }
}
}

我的问题是,一旦调用 getChatRooms 并第一次更改 chatRooms 数组,此后,每次 subscribeToChatRoomUpdates被调用不会重绘 ChatRoomView subview 。另一方面,ChatRoomsListView 得到正确更新。

为什么会发生这种情况?

最佳答案

我认为你的 Equatable 的实现- 它只比较 id已经打破了ChatView的能力检测 let chatRoom: ChatRoom 的更改,所以 SwiftUI 不会调用 body因为旧值和新值之间的 id 没有变化。尝试删除 Equatable .

顺便说一句,您需要取消订阅对象的 deinit 中的更新否则你可能会崩溃。以及您对 self? 的使用是有问题的,请查看 block 中的保留循环。

关于SwiftUI - @Published 数组不更新 subview ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73701900/

相关文章:

nsoperationqueue - 使用结合框架的操作队列

swiftui - 无法推断通用参数 'SelectionValue'

ios - SwiftUI在watchOS上通过NavigationLink列出性能下降

ios - 如何修改拖放预览SwiftUI 的背景颜色和形状?

scrollview - SwiftUI ScrollView : How to modify . content.offset 又名分页?

ios - SwiftUI @State 变量没有被取消初始化

ios - Xcode 12 SwiftUI 应用程序因 UIRequiredDeviceCapabilities plist 键而被拒绝

swift - ScrollView 导致 SwiftUI 中的错误按钮

Button Stroke Set Gap 在特定位置 Swiftui

ios - 是否可以在没有 Web 服务器的情况下创建 App Clip