Prevent scrolling when adding or updating UITableView with NSFetchedResultsController with autostart

I have a chat application that maintains a single section UITableViewController with a database. Based on push messages, I update the post status or add new posts. When a new message arrives, I would like to scroll to the bottom of the table. Each cell has a variable height, which is controlled by autoplay using:

self.tableView.estimatedRowHeight = 76
self.tableView.rowHeight = UITableViewAutomaticDimension

      

  • I am loading NSFetchRequest () in viewDidLoad which loads posts from the main data table and jumps to the last post in viewDidAppear. This works correctly when launched from Xcode, but if I launch the app on the iPhone instead, it doesn't go to the last message, but somewhere in the middle. Also, if I defer the message to the main thread, it still doesn't work. However, if I insert a small delay like this, it always works correctly:

    override func viewDidAppear(animated: Bool) {
      super.viewDidAppear(animated)
    
      // not sure why this delay is needed
    
      dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.001 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
        self.scrollToLastMessage()
      }
    }
    
          

    Of course I don't like the fixed delay, especially I don't understand. Is there a specific event I should be using to scroll to the last post?

  • More trouble, I can't seem to find a way to force NSFetchResultsController.Insert (append) or .Update a string without scrolling the UITableViewController elsewhere. I tried to grab and restore the contentOffset, which I have to animate: false to prevent very confusing animations, but the table still has visible scrolling flicker. I tried reloadData () for the whole table, reloadRowsAtIndexPaths () to just update the corresponding cell, with and without beginUpdates () / endUpdates (). I also tried scrollToRowAtIndexPath (lastRow). No matter what, I can't seem to get this simple update to work without the UITableView's offline scrolling. It seems to scroll the changed line to the middle of the screen with an animation, after which I have to scroll back to where it should be.Has anyone else noticed this? Is this scrolling artifact NSFetchResultsController, "function" UITableViewController, or result of using UITableViewAutomaticDimension?

    So far I am getting the best results with the following, but there is visible flicker.

    func controllerDidChangeContent(controller: NSFetchedResultsController!) {
      self.tableView.reloadData()
    }
    
    private func scrollToLastMessage() {
      dispatch_async(dispatch_get_main_queue()) {
    
        // without the check below, this oddly doesn't scroll to the right place (autolayout issue?)
    
        if self.tableView.contentSize.height > self.tableView.frame.size.height {
          let offset = CGPoint(x: 0, y: self.tableView.contentSize.height - self.tableView.frame.size.height)
          self.tableView.setContentOffset(offset, animated: false)
        }
      }
    }
    
          

  • When using UITableViewAutomaticDimension I notice that the offset of the last row changes. For example, if I ask for an offset in one go to navigate to the correct contentOffset to display it, the contentOffset might spontaneously change as the UITableViewController checks other cells for their heights and scrolling. Is there a way to prevent this? I. to get the UITableViewAutomaticDimension to always measure the actual heights of the cells, not the inferred heights, so I don't have to implement the rowHeight method? As mentioned above, I also tried scrollToRowAtIndexPath (lastRow), but it has the same strange scrolling behavior.

+3


source to share





All Articles