title: How to insert rows to the top of UITableView without scrolling the table?
body: <p>How to insert rows to the top of UITableView without scrolling the table? The same like when when you drag to reload new tweets on twitter or messages in whatsApp</p>
  
  <p>I tried doing another section of begin/endUpdate asking it to scroll to the 3rd index, but it didn't work. It always scrolls to the top of the tableView. I want it to stay at the same position as it was before adding the new rows.  </p>
  
  <pre><code>    self.tableView.beginUpdates()
      let indexPath = IndexPath(row: 3, section: 0)
      self.tableView.scrollToRow(at: indexPath, at: .top, animated: false)
      self.tableView.endUpdates()
  </code></pre>
  
  <p>P.S. this is a sample project in my real project the cells varies in size based on the message size.</p>
  
  <p>This is the link to the project:
  <a href="https://github.com/akawther/TableView" rel="noreferrer">https://github.com/akawther/TableView</a></p>
  
  <pre><code>import UIKit
  
  class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
  
  @IBOutlet weak var tableView: UITableView!
  var loadMore: UIRefreshControl!
  
  var labels = ["A","B","C","D","E","F","G","H","I","J","K"]
  
  override func viewDidLoad() {
      super.viewDidLoad()
  
      self.loadMore = UIRefreshControl()
      self.loadMore.attributedTitle = NSAttributedString(string: "Pull to reload more")
      self.loadMore.addTarget(self, action: #selector(ViewController.loadMoreChats), for: .valueChanged)
      self.tableView.addSubview(self.loadMore)
  
      // Do any additional setup after loading the view, typically from a nib.
  }
  
  func loadMoreChats() {
      DispatchQueue.main.async(execute: {() -&gt; Void in
          self.tableView.beginUpdates()
          self.labels.insert("3", at: 0)
          self.labels.insert("2", at: 0)
          self.labels.insert("1", at: 0)
          let indexPaths = [
              IndexPath(row: 0, section: 0),
              IndexPath(row: 1, section: 0),
              IndexPath(row: 2, section: 0),
          ]
          self.tableView.insertRows(at: indexPaths, with: .top)
          self.tableView.endUpdates()
          self.loadMore.endRefreshing()
  
          self.tableView.beginUpdates()
          let indexPath = IndexPath(row: 3, section: 0)
          self.tableView.scrollToRow(at: indexPath, at: .top, animated: false)
          self.tableView.endUpdates()
      })
  }
  
  
  override func didReceiveMemoryWarning() {
      super.didReceiveMemoryWarning()
      // Dispose of any resources that can be recreated.
  }
  
  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int {
      return labels.count
  }
  
  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -&gt; UITableViewCell {
      let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell") as! customCellTableViewCell
  
      cell.label.text = labels[indexPath.row]
      return cell
  }
  
  }
  </code></pre>
  
  <p><strong>UPDATE #1:</strong>
  I have just tried it also by surrounding my second being/end update with CATransaction, but still the top displayed is 1 instead of A like I want:</p>
  
  <pre><code>        CATransaction.begin()
          self.tableView.beginUpdates()
          CATransaction.setCompletionBlock { () -&gt; Void in
              let indexPath = IndexPath(row: 3, section: 0)
              self.tableView.scrollToRow(at: indexPath, at: .top, animated: false)
          }
          self.tableView.endUpdates()
          CATransaction.commit()
  </code></pre>
  
  <p><strong>UPDATE #2:</strong> 
  The github project is updated with the answer from @beyowulf</p>