这是我的模型:
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/