7

I have a UITableView which is displaying an aggregated feed of posts from several RSS feeds. Whenever my app pulls new posts from a feed, I create an object representing all of the needed insertions and deletions needed to update the UITableView current rows. I place these objects into an array which I use as a FIFO queue. Every few seconds, I pull the first element out of this array and attempt to perform all of the insertions and deletions within the UITableView using the function UITableView:performBatchUpdates.

This all works great ... so long as the user doesn't scroll the UITableView up and down. If there is scrolling going on, the updates will cease, because I am setting a flag to ensure that I always wait until the last set of insertions/deletions has completed before I start the next batch, and sadly, sometimes, the completion closure of UITableView:performBatchUpdates never gets called, hence my flag is never cleared.

Here is the code I'm using to process my incoming queue of changes for the UITableView:

@objc func updateFeedPostsTableView() {

    guard feedUpdateQueue.count > 0,
          !feedTableUpdateInProgress else { return }

    feedTableUpdateInProgress = true
    let feedUpdate = feedUpdateQueue.first!
    feedUpdateQueue.remove(at: 0)

    self.aggregatedRSSFeed = feedUpdate.feed

    self.feedPostsTableView.performBatchUpdates ({
        self.feedPostsTableView.deleteRows(at: feedUpdate.indexPathsOfDeletedPosts,
                                           with: .fade)
        self.feedPostsTableView.insertRows(at: feedUpdate.indexPathsOfNewPosts,
                                           with: .top)
        },
        completion: { (success) in
            self.feedTableUpdateInProgress = false
        }
    )
}

My question is, why would UITableView.performBatchUpdates ever fail to call its completion block? What am I doing wrong here?

This is iOS 11.2, using Xcode version 9.2.

Thanks!

Kuldeep
  • 4,466
  • 8
  • 32
  • 59
Greg Anderson
  • 540
  • 4
  • 14
  • Update: This gets worse. I tried replacing my test of !feedTableUpdateInProgress to instead examining the number of rows currently in the UITableView, the better to decide if I should proceed with the next set of updates. Alas, the number of total rows does not always eventually add up to the number of rows my app has requested to be inserted. – Greg Anderson May 22 '18 at 05:29
  • is your app crashing? I think app will be crashed if you just deleteRows while not removing from array itself – PPL May 22 '18 at 06:28
  • @PPL, no the app does not crash; I have calculated the arrays of deletions and insertions properly. In fact, I removed all deletions, as a test, and it turns out that row insertions are never performed if/when the tableview is being scrolled by the user. – Greg Anderson May 22 '18 at 06:29
  • can you share me your full code? so I can run it over here and test – PPL May 22 '18 at 06:32
  • For Simple UITableView, it is working in my code :) please share your code so I can run it over here and test – PPL May 22 '18 at 06:36

1 Answers1

7

I was having this problem. The main performBatchUpdates block was getting executed but the completion block was never called. I found out that the issue was caused by me using a subclass of UITableView. As soon as I switched back to a vanilla UITableView the problem went away.

Lesson learned. Don't subclass UITableView.

iamiend
  • 103
  • 1
  • 6