此问题在此处已有答案:
Accessing StateObject's object without being installed on a View. This will create a new instance each time - SwiftUI(3个答案)
18天前关闭
我对SwiftUI相当陌生,我正在尝试构建一个聊天室。当我向应用程序发送消息时,新消息不会显示,并且我在终端中收到一个警告,说“在未安装在View上的情况下删除StateObject的对象。这将每次创建一个新示例。”
import SwiftUI
import SocketIO
struct ChatMessage: Hashable {
var message: String
var MatchImg: String
var isMe: Bool
}
class ChatMessageList: ObservableObject {
@Published var list: [ChatMessage]
init(list: [ChatMessage]) {
self.list = list
}
func addItem(item: ChatMessage) {
list.append(item)
objectWillChange.send()
}
}
struct MessageView: View {
@State private var showMenu: Bool = false
@StateObject var messages = ChatMessageList(list: [
ChatMessage(message: "Hello world", MatchImg:"ye",isMe: true),
ChatMessage(message: "Hello world", MatchImg:"ye",isMe: false)
])
@State private var composedMessage: String = ""
let roomID: String
let userID: String
let otherUser: String
private var socket: SocketIOClient
private var manager: SocketManager
init(roomID: String, userID: String, otherUser: String) {
self.roomID = roomID
self.userID = userID
self.otherUser = otherUser
self.manager = SocketManager(socketURL: URL(string: "http://localhost:8080")!, config: [.log(false), .compress])
self.socket = self.manager.defaultSocket
self.socket.connect()
self.addHandlers()
}
func addHandlers() {
self.socket.on("chat message") { data, ack in
let messageText = data[0]
let newMessage = ChatMessage(message: messageText as! String, MatchImg: "ye", isMe: false)
addMessage(message: newMessage)
// DispatchQueue.main.async {
// self.messages.list.append(newMessage)
// }
}
}
func addMessage(message: ChatMessage) {
DispatchQueue.main.async {
messages.addItem(item: message)
}
}
var body: some View {
VStack {
VStack(alignment: .center){
//omitted
}
List{
ForEach(messages.list, id: \.self) { msg in
ChatRow(chatMessage: msg)
.listRowSeparator(.hidden)
.listRowBackground(Color.clear)
}
}
.padding(0)
.listStyle(PlainListStyle())
.environment(\.defaultMinListRowHeight, 0)
HStack {
TextField("Message...", text: $composedMessage).frame(minHeight: CGFloat(36))
.padding(.horizontal,12)
.overlay(
RoundedRectangle(cornerRadius: 15)
.stroke(Color.blue, lineWidth: 2)
)
Button("Send"){
Task {
self.socket.emit("message", roomID, composedMessage)
self.messages.addItem(item: ChatMessage(message: composedMessage, MatchImg: "ye", isMe: true))
print(self.messages)
self.composedMessage = ""
}
}
Button("add") {
showMenu.toggle()
}
Button(action: {}){
Image("person.fill")
.foregroundColor(Color.black)
}
}.padding(20)
.task{
print(self.socket.status)
self.socket.emit("identify", userID)
self.socket.emit("subscribe", roomID, otherUser)
}
}
}
}
}
struct ChatRow : View {
var chatMessage: ChatMessage
var body: some View {
if !chatMessage.isMe {
HStack {
// omitted
}
}
else {
// omitted
}
}
}
字符串
我试过
- 使用
DispatchQueue.main.async
- 编写一个单独的函数来添加新消息(
addMessage()
) - 在类
ChatMessageList
中编写一个函数
我在添加了一个新项目后打印了状态对象,但是没有新的消息。但是在发送新消息时,上面的所有功能似乎都工作得很好。
1条答案
按热度按时间hgqdbh6s1#
你不应该在
View
结构体中初始化像SocketManager这样的对象,你也不能在View
结构体中使用DispatchQueue.main.async
。View
数据结构体只是简单的值,它们会被生成、区分和销毁。所以如果你在它们中创建对象,它会被认为是内存泄漏,如果它真的这样做了,调度器将返回到一些旧的丢失的View
结构体上。