【发布时间】:2016-02-16 16:17:57
【问题描述】:
我在它下面有一个搜索栏和一个表格视图。当我搜索某些东西时,会进行网络调用并将 10 个项目添加到数组中以填充表。当我滚动到表格底部时,又对另外 10 个项目进行了网络调用,所以现在数组中有 20 个项目...这可以继续,因为它是类似于 Facebook 的新闻提要的无限滚动。
每次进行网络调用时,我也会在主线程上调用self.tableView.reloadData()。 由于每个单元格都有一个图像,您可以看到闪烁 - 单元格图像闪烁白色。
我尝试实现this solution,但我不知道将它放在我的代码中的哪个位置或如何放置。我的代码是 Swift,那就是 Objective-C。
有什么想法吗?
问题 1 更新
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(R.reuseIdentifier.searchCell.identifier, forIndexPath: indexPath) as! CustomTableViewCell
let book = booksArrayFromNetworkCall[indexPath.row]
// Set dynamic text
cell.titleLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline)
cell.authorsLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleFootnote)
// Update title
cell.titleLabel.text = book.title
// Update authors
cell.authorsLabel.text = book.authors
/*
- Getting the CoverImage is done asynchronously to stop choppiness of tableview.
- I also added the Title and Author inside of this call, even though it is not
necessary because there was a problem if it was outside: the first time a user
presses Search, the call for the CoverImage was too slow and only the Title
and Author were displaying.
*/
Book.convertURLToImagesAsynchronouslyAndUpdateCells(book, cell: cell, task: task)
return cell
}
cellForRowAtIndexPath 在里面使用这个方法:
class func convertURLToImagesAsynchronouslyAndUpdateCells(bookObject: Book, cell: CustomTableViewCell, var task: NSURLSessionDataTask?) {
guard let coverImageURLString = bookObject.coverImageURLString, url = NSURL(string: coverImageURLString) else {
return
}
// Asynchronous work being done here.
task = NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: { (data, response, error) -> Void in
dispatch_async(dispatch_get_main_queue(), {
// Update cover image with data
guard let data = data else {
return
}
// Create an image object from our data
let coverImage = UIImage(data: data)
cell.coverImageView.image = coverImage
})
})
task?.resume()
}
当我滚动到表格底部时,我会使用willDisplayCell 检测是否到达底部。如果是底部,那么我再次进行相同的网络调用。
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row+1 == booksArrayFromNetworkCall.count {
// Make network calls when we scroll to the bottom of the table.
refreshItems(currentIndexCount)
}
}
这是网络调用代码。当我在搜索栏上按 Enter 时第一次调用它,然后每次到达单元格底部时都会调用它,如您在 willDisplayCell 中看到的那样。
func refreshItems(index: Int) {
// Make to network call to Google Books
GoogleBooksClient.getBooksFromGoogleBooks(self.searchBar.text!, startIndex: index) { (books, error) -> Void in
guard let books = books else {
return
}
self.footerView.hidden = false
self.currentIndexCount += 10
self.booksArrayFromNetworkCall += books
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
}
【问题讨论】:
-
能否在创建单元格时显示代码(cellForRowAtIndexPath)?我以前做过这种搜索,我没有这个问题。如果只有图像闪烁白色,而旁边的文本没有闪烁,则可能当您调用 reloadData() 时,图像会再次从源下载,这会导致闪烁。在这种情况下,您可能需要将图像保存在缓存中。
-
@OscarJ.Irun 请查看更新后的问题,我添加了您要求的代码。再次查看应用程序后,只有图像闪烁白色,而不是文字。你会如何解决这个问题?
-
是的,我猜它每次调用
reloadData()时都会从源下载图像。我建议使用SDWebImage 来缓存图像并异步下载。它非常简单,我在大多数项目中都使用它。要确认是这种情况,只需将您的资产中的静态图像添加到单元格中,而不是调用convertURLToImagesAsynchronouslyAndUpdateCells,您将看到它不会再次闪烁。 -
@OscarJ.Irun 你说得对,当我添加静态图像时,它不再闪烁。我以前从未做过图像缓存,听起来很复杂。你有什么推荐的 Swift 教程吗?另外,这是解决此问题的唯一方法吗?谢谢!
-
该库完成了所有艰苦的工作。我没有在 Swift 中编程,但我认为它就像
cell.imageView.sd_setImageWithURL(myImageURL)一样简单。它已经完成了!检查此链接SDWebImage in Swift
标签: ios swift uitableview networking reloaddata