有没有办法使用 SwiftUI 和 Firebase 动态地在属性初始化程序中的实例中赋予初始值?

Posted

技术标签:

【中文标题】有没有办法使用 SwiftUI 和 Firebase 动态地在属性初始化程序中的实例中赋予初始值?【英文标题】:Is there a way to give initial value in an instance in property initializer dynamically using SwiftUI and Firebase? 【发布时间】:2020-04-29 04:07:22 【问题描述】:

您好,我目前正在制作一个约会应用的聊天页面,您可以使用 SwiftUI 和 Cloud Firestore 为每场比赛设置不同的房间。

我想根据 matchId 每次点击首页上的不同用户时显示不同的聊天室。

现在,我需要在视图文件中键入正确的,以使其正常工作,但是,我想动态分配它。

如何将正确的 matchId 添加到视图文件中的实例?或者,我应该尝试不同的方式吗?

首先,这是首页。

VStack
         Text("Match Users")
         List(self.shareData.matchUserArray) user in
            NavigationLink(destination: MessageView(matchUserInfo: user))
               HStack
                  Text(user.name)
                  Text(user.age)
               
             
           
         

这是视图文件。无需在 MessageViewModel 实例中键入“Ll73RINefGxEcYQJoWSE”而是给它“”,我可以在调试区域中看到消息,但在列表中看不到任何消息。

struct MessageView: View 
    var matchUserInfo: User

    @ObservedObject var msgVM = MessageViewModel(matchId: "Ll73RINefGxEcYQJoWSE")

    @EnvironmentObject var shareData : ShareData
    @State var text = ""

    @State var matchId = ""
    var body: some View 
        VStack
            List(self.msgVM.messages, id: \.id) i in
                if i.fromUser == self.shareData.currentUserData["id"] as? String ?? ""
                
                    MessageRow(message: i.msg, isMyMessage: true)
                 else if  i.toUser == self.shareData.currentUserData["id"] as? String ?? ""
                
                    MessageRow(message: i.msg, isMyMessage: false)
                
                
            .onAppear  UITableView.appearance().separatorStyle = .none 
            .onDisappear  UITableView.appearance().separatorStyle = .singleLine 

            HStack
                TextField("message here", text: $text).textFieldStyle(RoundedBorderTextFieldStyle()).padding()
                Button(action: 
                    if self.text.count > 0 
                          self.msgVM.sendMsg(msg: self.text, toUser: self.matchUserInfo.id, fromUser: self.shareData.currentUserData["id"] as! String, matchId: self.msgVM.matchId)

                        self.text = ""
                    

                ) 
                    Image(systemName: "paperplane")
                .padding(.trailing)
            

        
        .navigationBarTitle("\(self.matchUserInfo.name)", displayMode: .inline)
            .onAppear
                DispatchQueue.global().async
                self.getMatchId(partner: self.matchUserInfo)
                
                _ = MessageViewModel(matchId: self.matchId)

        


        .onDisappear
          print(self.msgVM.messages)
        
    

    func getMatchId(partner: User)
        Firestore.firestore().collection("MatchTable").document(self.shareData.currentUserData["id"] as? String ?? "").collection("MatchUser").whereField("MatchUserId", isEqualTo: partner.id).getDocuments  (snap, err) in
            if let snap = snap 
                for id in snap.documents
                    self.msgVM.matchId = id.data()["MatchRoomId"] as? String ?? ""
                    _ = MessageViewModel(matchId: self.msgVM.matchId)
                    self.matchId = self.msgVM.matchId
                
            

        

    


这也是 firebase 部分。

import Foundation
import FirebaseFirestore

struct Message: Identifiable 
    var id: String
    var msg: String
    var fromUser: String
    var toUser: String
    var date: Timestamp
    var matchId : String



class MessageViewModel: ObservableObject 
    var datas = FirebaseData()
    let db = Firestore.firestore()

    @Published var matchId:String

    @Published var messages = [Message]()

    init(matchId: String)
        self.matchId = matchId

        self.db.collection("Messages").whereField("matchId", isEqualTo: self.matchId).order(by: "date").addSnapshotListener  (snap, error) in

            if let error = error 
                print(error.localizedDescription)
                return
            

            if let snap = snap 
                for i in snap.documentChanges 

                    if i.type == .added
                        let toUser = i.document.get("toUser") as! String
                        let fromUser = i.document.get("fromUser") as! String
                        let message = i.document.get("message") as! String
                        let id = i.document.documentID
                        let date = i.document.get("date") as! Timestamp
                        let matchId = i.document.get("matchId") as! String

                        self.messages.append(Message(id: id, msg: message, fromUser: fromUser, toUser: toUser, date: date, matchId: matchId))

                    
                
            
        
    




    func sendMsg(msg: String, toUser: String, fromUser: String, matchId: String)

        let data = [
            "message": msg,
            "toUser": toUser,
            "fromUser": fromUser,
            "date": Timestamp(),
            "matchId": matchId
            ] as [String : Any]

        Firestore.firestore().collection("Messages").addDocument(data: data) error in
            if let err = error 
                print(err.localizedDescription)
                return
            
            print("Sent message")
        





谢谢

【问题讨论】:

【参考方案1】:

您真正需要的是在init 函数中构造您的ObservedObject

let matchUserInfo: User

@ObservedObject private var msgVM: MessageViewModel

init(_ user: User) 
    self.matchUserInfo = user
    self._msgVM = ObservedObject(initialValue: MessageViewModel(matchId: user.matchId))

当然,假设您关心的 matchId 是通过您的 User 类型传入的。你比我更了解你的数据结构,这里的关键是根据你传入的 User 简单地创建你观察到的对象。

【讨论】:

我对 matchUserArray 的元素进行了一些更改,以便每个传入的用户都有 matchId,并且一切都开始运行良好。非常感谢,它很有帮助! @Procrastin8

以上是关于有没有办法使用 SwiftUI 和 Firebase 动态地在属性初始化程序中的实例中赋予初始值?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法使用几何阅读器将我的 SwiftUI 图像的宽度定义为相对于屏幕尺寸?

有没有办法为 SwiftUI 菜单使用 .displayInline 选项?

有没有办法在 macOS SwiftUI 开发中使用 SF Symbols?

SwiftUi 有没有办法在 TextField 中获取文本

有没有办法可以使用 SwiftUI 将文本限制为 2 / 3 行?

SwiftUI - 有没有办法创建一个只读的 TextEditor?