重新加载表会导致闪烁

时间:2016-02-16 16:17:57

标签: ios swift uitableview networking reloaddata

我有一个搜索栏和一个表格视图。当我搜索网络调用的内容并将10个项目添加到数组以填充表格时。当我滚动到桌子的底部时,另外10个项目的另一个网络呼叫,所以现在阵列中有20个项目...这可以继续,因为它是一个类似于Facebook的无限滚动&#39新闻提要。

每次拨打网络电话时,我也会在主线程上拨打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()
        }
    }
}

3 个答案:

答案 0 :(得分:2)

如果只有图像闪烁白色,而旁边的文字没有,则可能在您拨打convertURLToImagesAsynchronouslyAndUpdateCells时,会再次从信号源下载图像,从而导致闪光。在这种情况下,您可能需要将图像保存在缓存中。

我建议使用SDWebImage来缓存图像并异步下载。这很简单,我在大多数项目中使用它。要确认是这种情况,只需将资源中的静态图片添加到单元格,而不是调用cell.imageView.sd_setImageWithURL(myImageURL),您将看到它不会再次闪烁。

我不会在Swift中编程,但我发现它就像<<instance>>一样简单。它已经完成了!

答案 1 :(得分:1)

尝试在调用[tableView reloadData] method..Like

之前和之后更改表alpha值
dispatch_async(dispatch_get_main_queue()) {
            self.aTable.alpha = 0.4f;
            self.tableView.reloadData()
            [self.aTable.alpha = 1.0f;

        }

我在UIWebView重新加载中使用了相同的方法..这对我有用。

答案 2 :(得分:1)

以下是使用insertRowsAtIndexPaths(_:withRowAnimation:)

进行无限滚动的示例
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet weak var tableView: UITableView!

    var dataSource = [String]()
    var currentStartIndex = 0

    // We use this to only fire one fetch request (not multiple) when we scroll to the bottom.
    var isLoading = false

    override func viewDidLoad() {
        super.viewDidLoad()

        // Load the first batch of items.
        loadNextItems()
    }

    // Loads the next 20 items using the current start index to know from where to start the next fetch.
    func loadNextItems() {

        MyFakeDataSource().fetchItems(currentStartIndex, callback: { fetchedItems in

            self.dataSource += fetchedItems // Append the fetched items to the existing items.

            self.tableView.beginUpdates()

            var indexPathsToInsert = [NSIndexPath]()
            for i in self.currentStartIndex..<self.currentStartIndex + 20 {
                indexPathsToInsert.append(NSIndexPath(forRow: i, inSection: 0))
            }
            self.tableView.insertRowsAtIndexPaths(indexPathsToInsert, withRowAnimation: .Bottom)
            self.tableView.endUpdates()

            self.isLoading = false

            // The currentStartIndex must point to next index.
            self.currentStartIndex = self.dataSource.count
        })
    }

    // #MARK: - Table View Data Source Methods

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dataSource.count
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = UITableViewCell()
        cell.textLabel!.text = dataSource[indexPath.row]
        return cell
    }

    // #MARK: - Table View Delegate Methods

    func scrollViewDidScroll(scrollView: UIScrollView) {
        if isLoading == false && scrollView.contentOffset.y + scrollView.bounds.size.height > scrollView.contentSize.height {
            isLoading = true
            loadNextItems()
        }
    }
}

MyFakeDataSource无关紧要,可能是您的GoogleBooksClient.getBooksFromGoogleBooks或您正在使用的任何数据源。