为什么实例变量在闭包内有不同的值?

时间:2017-08-20 16:13:06

标签: ios swift uitableview alamofire

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在闭包内外也有不同的值。

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

P.S。我不知道提及这会有什么不同,但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
        }
    }

2 个答案:

答案 0 :(得分:0)

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

这被称为异步功能,它通常会绊倒之前没有看过它的人,但最终会看到很多,所以值得一读。

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

答案 1 :(得分:0)

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

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

在Yelp响应之后,闭包被执行。并且计数为3,打印出来。

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

编辑:

我认为你写的事实

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

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