为啥实例变量在闭包内具有不同的值?
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
。我也在使用SwiftyJSON
和Alamofire
。
更新:
我的表格视图数据源方法是:
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 外部的打印语句。发布您的 cellforRow
和 noOfRowsInSection
方法,我认为这些方法导致崩溃..
@Bilal 用表格视图数据源方法更新了我的问题。
【参考方案1】:
因为completion
块的工作是在网络调用完成时向您报告。 HTTPHelper
正在调用服务器,这可能需要相当长的时间。它不会阻止您的程序执行,而只是在该行等待:它立即转到下一行并调用print("Number of comments: \(self.comments.count)")
,您得到0,因为网络调用尚未完成。然后,一段时间后,整个completion
块发生了。
这被称为异步函数,它通常会让以前没见过它的人绊倒,但你最终会看到很多,所以值得一读。
您说“当我在闭包中添加 tableView.reloadData() 时出现index out of bounds for an empty array
错误”,这听起来像是配置表的 UITableViewDataSource 函数之一(cellForRowAt
、numberOfRowsInSection
) ,某处有错误。
【讨论】:
用我的表格视图数据源方法更新了我的问题。【参考方案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 如果是这种情况,那么我认为您应该进行一些调试。转到发生错误的行并打印该行上的所有值。这些是基本的调试技能,您应该学习它们。无论如何,我认为讨论已经超出了这个问题的范围。如果调试后仍然无法弄清楚问题所在,请尝试发布另一个问题。以上是关于为啥实例变量在闭包内具有不同的值?的主要内容,如果未能解决你的问题,请参考以下文章