为啥实例变量在闭包内具有不同的值?

Posted

技术标签:

【中文标题】为啥实例变量在闭包内具有不同的值?【英文标题】:Why does an instance variable have a different value inside of a closure?为什么实例变量在闭包内具有不同的值? 【发布时间】:2017-08-20 16:13:05 【问题描述】:
func loadYelpComments()
        guard let business = business else return
        guard let _ = tableView else return
        guard let businessID = business.id else return
        let dateFormatter = DateFormatter()
        dateFormatter.dateStyle = .full

        HTTPHelper.getYelpComments(for: businessID, completionHandler:  data in
            let json = JSON(data)
            let reviews = json["reviews"].arrayValue.map(return $0.dictionaryValue)
            var commentDate: Date?


            for (index, review) in reviews.enumerated()
                let userDictionary = review["user"]?.dictionary
                if let dateString = review["time_created"]?.stringValue
                    commentDate = dateFormatter.date(from: dateString)
                

                let yelpComment = YelpComment(rating: review["rating"]?.intValue, userImageURL: userDictionary?["image_url"]?.stringValue, userName: userDictionary?["name"]?.stringValue, comment: review["text"]?.stringValue, commentDate: commentDate, commentPageURL: review["url"]?.stringValue)

                self.comments.append(yelpComment)
            

            print("Number of comments: \(self.comments.count)") //Prints: Number of comments: 3"
            self.tableView.reloadData()

        )

            print("Number of comments: \(self.comments.count)") //This prints firt "Number of comments: 0"

    

getYelpComments(for:completionHandler:) 类方法负责从 Yelp API 获取 JSON 数据。令我惊讶的是,即使 comments 实例数组正在通过向其附加新的 YelpComment 对象来更新,它的 count 在闭包内部和外部具有不同的值。

这些 cmets 应该显示在表格视图中。更让我困惑的是,当我在闭包中添加tableView.reloadData() 时,我得到一个index out of bounds for an empty array 错误,但是当我添加相同的代码行时:tableView.reloadData() 在闭包之外我没有得到任何错误,comments.count等于零。任何帮助将非常感激!

附:我不知道提到这是否会有所作为,但data@escaping。我也在使用SwiftyJSONAlamofire

更新:

我的表格视图数据源方法是:

   override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 

        if section == 0 
            return super.tableView(tableView, numberOfRowsInSection: section)
         else 
            return comments.count
        

    

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 

        if indexPath.section == 0 
            return super.tableView(tableView, cellForRowAt: indexPath)
         else 
            let cell = tableView.dequeueReusableCell(withIdentifier: CustomCellTypeIdentifiers.YelpCommentCell, for: indexPath) as! YelpCommentCell
            cell.configureYelpCell(with: comments[indexPath.row])
            return cell
        
    

【问题讨论】:

getYelpComments 是一个异步调用。在闭包中的代码运行之前执行 cloure 外部的打印语句。发布您的 cellforRownoOfRowsInSection 方法,我认为这些方法导致崩溃.. @Bilal 用表格视图数据源方法更新了我的问题。 【参考方案1】:

因为completion 块的工作是在网络调用完成时向您报告。 HTTPHelper 正在调用服务器,这可能需要相当长的时间。它不会阻止您的程序执行,而只是在该行等待:它立即转到下一行并调用print("Number of comments: \(self.comments.count)"),您得到0,因为网络调用尚未完成。然后,一段时间后,整个completion 块发生了。

这被称为异步函数,它通常会让以前没见过它的人绊倒,但你最终会看到很多,所以值得一读。

您说“当我在闭包中添加 tableView.reloadData() 时出现index out of bounds for an empty array 错误”,这听起来像是配置表的 UITableViewDataSource 函数之一(cellForRowAtnumberOfRowsInSection) ,某处有错误。

【讨论】:

用我的表格视图数据源方法更新了我的问题。【参考方案2】:

闭包不一定会在您看到它们时立即执行。

在您的代码中,闭包外的print 将在闭包内的print 之前执行。这是因为getYelpComments 是所谓的“异步方法”。在您等待 Yelp 服务器响应时,代码不会只是坐在那里无所事事。闭包后继续执行代码,打印计数为0。

在 Yelp 响应后,关闭被执行。并打印计数为 3。

至于为什么放tableView.reloadData()会导致它崩溃,可能是你的表视图数据源方法有问题。它很可能是 1 倍差。

编辑:

我认为你写的事实

if section == 0 
    return super.tableView(tableView, numberOfRowsInSection: section)

很奇怪。我不知道如果部分为 0,您为什么要返回 super 实现。您的表格视图是否有多个部分?如果没有,您可能应该删除检查。如果是,则正确返回第一部分的值。

【讨论】:

用我的表格视图数据源方法更新了我的问题。 第一部分由静态单元格组成,这就是我称之为超级的原因。第二部分意味着在 cmets 所在的位置具有动态单元格。 @A.Jam 如果是这种情况,那么我认为您应该进行一些调试。转到发生错误的行并打印该行上的所有值。这些是基本的调试技能,您应该学习它们。无论如何,我认为讨论已经超出了这个问题的范围。如果调试后仍然无法弄清楚问题所在,请尝试发布另一个问题。

以上是关于为啥实例变量在闭包内具有不同的值?的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript中的“闭包”

为啥 C++11 中捕获的变量在捕获中具有不同的值?

PHP匿名函数闭包function use

js重点知识总结

为啥我的实例变量在我的 Rails 视图中总是 Nil

为啥在 Student(Student s) 中可以使用实例变量? [复制]