【问题标题】:SwiftUI - Is it possible to update initialized parameters?SwiftUI - 是否可以更新初始化参数?
【发布时间】:2021-09-21 06:56:39
【问题描述】:

在我的代码中,我将 post.id 从视图传递到我的视图模型。为了让我的 cmets 出现,我需要初始化 getComments。以前,在我通过post.id 之前,我只是有init(){getComments(id: "E1m3U1FoeCbOwBGPPq4S")} 这条线。 E1m3U1FoeCbOwBGPPq4S 是一个已经包含 cmets 的文档,因此我可以测试以确保实际加载了 cmets。

现在,由于每个帖子都有一组不同的 cmets,我需要根据用户请求 cmets 的帖子更改 id。为此,就像我说的那样,我正在传递 post.id 并打印它(以确保它实际上已通过)。

在我的代码中,需要 init() 来显示 cmets。由于我的 cmets 的显示方式,初始化 getComments 是一项要求。如果没有 init,cmets 会显示一个 ProgressView 并且无处可去。

我的问题是,我可以更新初始化参数吗?如果我正在初始化getComments(id: "E1m3U1FoeCbOwBGPPq4S"),是否可以将E1m3U1FoeCbOwBGPPq4S 更新为传递的post.id?

我不能只将它设置为getComments(id: post.id),因为默认情况下,没有传递任何 ID,所以我得到 Thread 1: Nil 错误。我想我需要一个在用户单击 cmets 按钮时更新的默认值。

CommentsViewModel.swift

class CommentsViewModel : ObservableObject{
    
    @Published var comments: [CommentsModel] = []
    @Published var noComments = false
    @Published var newComment = false
    @Published var commentTxt = ""

    let ref = Firestore.firestore()
    let uid = Auth.auth().currentUser!.uid

    var post: PostModel? {
        didSet{
            if let post = self.post {
                getComments(id: post.id)
            }
        }
    }
    
    init(){getComments(id: "E1m3U1FoeCbOwBGPPq4S")}

    func getComments(id: String) {
        print("ID from getComments is: \(id)")
    }

CommentsView.swift - 显示 ProgressView 并显示 cmets

@StateObject var commentsData = CommentsViewModel()
if commentsData.comments.isEmpty{
                
                Spacer(minLength: 0)
                
                if commentsData.noComments{
                    Text("No Comments")
                }
                else{
                    Text("Test")
                }
                Spacer(minLength: 0)
            }
            else{
ScrollView{
                    VStack(spacing: 15){
                        
                        ForEach(commentsData.comments){comment in
                            
                            CommentsRow(post: post, comment: comment, commentData: commentsData)
                            
                        }
                    }
                    .padding()
                    .padding(.bottom,55)
                }
                .onAppear {
                  commentsData.post = post
                }

PostRow.swift - 实际显示 cmets 的按钮

    var CommentsData: CommentsViewModel
    @State private var showingComments = false
 Button(action: {
                    showingComments = true
                    commentsData.getComments(id: post.id)
                }){
                    Text("Comments")
                }
                .transition(.move(edge: .leading))
                .sheet(isPresented: self.$showingComments)
                {
                    CommentsView(post: post)
                }

编辑:init(){getComments(id: "E1m3U1FoeCbOwBGPPq4S")}if let post = self.post {getComments(id: post.id)} 都在控制台中打印,但 E1m3U1FoeCbOwBGPPq4S 是实际用于显示 cmets 的 ID。

【问题讨论】:

  • 你在 PostRow.swift 中的 commentsData 上调用 getComments,但这是 commentsData 的不同实例,而不是 CommentsView 中的实例,对吧?我很确定这可以解释您从一开始就遇到的问题。您需要在 CommentsView.swift 内部的 CommentsViewModel 实例上调用 getComments -- 现在,您在 PostRow 拥有的实例上调用它,这不一样.
  • 这可以解释为什么需要init 的误解,因为init 是在CommentsView 的版本上唯一 调用的东西。在 Swift 中没有初始化函数这样的事情,所以在 init 中做某事并没有赋予它特殊的属性。但是,在这种情况下,它可能是唯一真正发生的事情。如果comments.isEmptytrue,则onAppear 永远不会被调用。
  • 哦,这很有意义。如何从 CommentsViewModel 的实例中调用 getComments?你的回答对我来说很有意义。虽然,我认为 onAppear 被调用了?不完全确定。
  • onAppear 中调用它,但要确保它会发生在某个实际会被调用的地方。现在,如果comments.isEmpty,它永远不会被调用。您应该能够使用调试器来查看当前的调试器是否被调用,但我不知道它是如何实现的——它看起来像是在 else 块内。或者,其他简单的调试:使用print语句查看。
  • 好吧,我在 ScrollView 的 .onAppear 中添加了打印 - 没有打印任何内容。所以你是对的,它没有被调用。

标签: ios xcode firebase swiftui


【解决方案1】:

在您当前的设置中,您有不同的 CommentsViewModel 实例。当Button 被按下时,getComments 会被调用,但它是在与CommentsView 不同的实例上调用的。

CommentsView 内部,您当前的代码仅在 cmets 已经存在时调用 getComments。如果您将getComments 和周围的onAppear 移动到可以可靠调用的位置,您的代码应该开始工作。

【讨论】:

  • 好吧,现在这确实有效,我面临另一个错误。当我使用 cmets 打开帖子,然后关闭 CommentsView,然后重新打开它时,cmets 重新加载,因此每个评论有两个。如果你再做一次,你会得到每条评论三个,等等。
  • 听起来像是再次使用调试器查看何时创建视图模型、何时设置 cmets 等的好机会。但是,我相信这是一个单独的问题。
  • 我现在正试图弄清楚。如果我无法弄清楚,我会提出一个新问题。我只是不想发布大量问题并惹恼人们
  • 发布多个问题并不是一件坏事,只要它们是独一无二的。尽可能多地创建minimal reproducible example 也很有帮助。在这种情况下,这个问题随着时间的推移有多次迭代,当它们被删除时令人沮丧,在未来的版本中删除上下文和对话。我想如果在包含的代码中很清楚,我可能会在早期发现 CommentsViewModel 的不同实例的问题。
  • 好的。感谢您提供的信息 - 以后我会尝试发布更多包含我的问题的代码,以便他们可以理解。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-24
  • 1970-01-01
  • 1970-01-01
  • 2016-02-19
相关资源
最近更新 更多