访问闭包Swift3之外的变量

Posted

技术标签:

【中文标题】访问闭包Swift3之外的变量【英文标题】:Accessing a variable outside closure Swift3 【发布时间】:2017-04-21 00:47:34 【问题描述】:

我已经在 ViewController 类的开头声明了 requestPostArray。我正在尝试从数据库“Request Posts”中填充 requestPostArray,然后从 requestPostArray 中填充 tableView。但是,当我打印它的大小时,它显示为 0。任何帮助将不胜感激。

此外,下面的整个 else 语句都在另一个闭包中。

else 

            ref.child("Request Posts").observe(.value, with:  (snapshot) in
                let count = Int(snapshot.childrenCount)

                // Request Post database is empty
                if count == 0 
                    cell.nameLabel.text = "No requests so far."
                    cell.userNameLabel.isHidden = true
                    cell.numberOfRequestsLabel.isHidden = true
                

                // Request Post data is populated
                else 

                    var requestPostArray: [RequestPost]? = []
                    self.ref.child("Request Posts").observe(.value, with:  (snapshot) in
                        if let result = snapshot.children.allObjects as? [FIRDataSnapshot] 

                            for child in result 
                                let post = RequestPost(snapshot: child)
                                requestPostArray?.append(post)
                            
                        

                        else 
                            print("No Result")
                        
                    )


                    print("RequestPostArray size = \(requestPostArray?.count ?? 90)")

                    cell.nameLabel.text = self.requestPostArray?[indexPath.row].name
                    cell.userNameLabel.text = self.requestPostArray?[indexPath.row].name
                    cell.numberOfRequestsLabel.text = self.requestPostArray?[indexPath.row].name
                
            )
        

【问题讨论】:

【参考方案1】:

observe 块是异步的。在 requestPostArray?.append(post) 行修改之前,您正在阅读 requestPostArray

如果没有更多上下文,很难知道您希望如何在此 cell 对象上填充值,但如果您需要“请求帖子”,则必须等到您能够获得它们。

【讨论】:

谢谢乔纳!我做“请求帖子”数据库。我创建了一个名为“RequestPost”的自定义类型对象,我想将数据库中的所有子对象存储到一个名为 requestPostArray 的 RequestPost 数组中,其成员将填充表格单元格。我究竟如何“等到你能够获得它们”。是否有一个特定的函数只在块完成执行后触发? 您似乎正试图在表视图数据源的 cellForRowAtIndexPath 内进行异步查询。这是行不通的,因为cellForRowAtIndexPath 需要立即得到结果并且不会等待您的查询运行。而是考虑如何设计FUITableViewDataSource (github.com/firebase/FirebaseUI-ios/tree/master/…) 来解决这个问题。【参考方案2】:

这是应该发生的,因为观察函数是异步的,而您的其余代码是同步的,此外,如果您从 requestPostArray? 中删除可选的 unwrap,您将得到一个 nil 异常,因为异步任务需要时间来执行所以编译器将在它之前执行 snyc 任务。 基本上你要做的就是以下

 else 

                ref.child("Request Posts").observe(.value, with:  (snapshot) in
                    let count = Int(snapshot.childrenCount)

                    // Request Post database is empty
                    if count == 0 
                        cell.nameLabel.text = "No requests so far."
                        cell.userNameLabel.isHidden = true
                        cell.numberOfRequestsLabel.isHidden = true
                    

                    // Request Post data is populated
                    else 

                        var requestPostArray: [RequestPost]? = []
                        self.ref.child("Request Posts").observe(.value, with:  (snapshot) in
                            if let result = snapshot.children.allObjects as? [FIRDataSnapshot] 

                                for child in result 
                                    let post = RequestPost(snapshot: child)
                                    requestPostArray?.append(post)
                                
                            

                            else 
                                print("No Result")
                            
print("RequestPostArray size = \(requestPostArray?.count ?? 90)")

                        cell.nameLabel.text = self.requestPostArray?[indexPath.row].name
                        cell.userNameLabel.text = self.requestPostArray?[indexPath.row].name
                        cell.numberOfRequestsLabel.text = self.requestPostArray?[indexPath.row].name
                        )



                    
                )
            

另一个建议是考虑使用单例,这样您就可以获得对象的重用,并且您不会像现在那样以相同的方法多次调用数据库。

【讨论】:

谢谢Achref!我对 Swift 比较陌生,所以我不太确定单例是什么。您能否简要地告诉我它是什么或指向我可以找到更多信息的链接?谢谢 请看这里***.com/a/43513805/4442592,我包含了一个完整的例子,更多细节我想邀请你阅读这个很棒的教程:raywenderlich.com/86477/… 我的回答有帮助吗? 是的,您的回答很有帮助。它确实有效,但事实证明我必须手动设置表的 numberOfRowsInSection() 才能显示正确的行数。我目前正在尝试将数据库中的帖子数量存储在一个变量中,然后在 numberOfRowsInSection() 函数中返回它。 这是另一个问题,请将此问题标记为已解决并提出一个新问题。

以上是关于访问闭包Swift3之外的变量的主要内容,如果未能解决你的问题,请参考以下文章

理解闭包

在 Swift 3 中附加一个函数范围之外的变量

JS封闭函数闭包内置对象

JS:闭包小结

javascript 闭包

闭包与私有变量