title: UICollectionView cells only display after second call to reloadData
body: <p>I'm probably doing something incredibly stupid, but I can't figure out for the life of me what's going on...</p>
  
  <p>What I'm trying to do is quite simple. I have a <code>UICollectionView</code> dependent on data I'm loading from the server. After I get and set the data from the server, I call <code>reloadData()</code> on the collection view. When I do so, <code>numberOfItemsInSection</code> is called with the correct count, but <code>cellForItemAt</code> never gets called unless I call <code>reloadData()</code> for a second time (doesn't even need a delay).</p>
  
  <p>Here's the general idea (although I realize it's likely related to some race conditional elsewhere, but maybe this will be enough to start the conversation):</p>
  
  <pre><code>class MyViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
  
      @IBOutlet weak var collectionView: UICollectionView!
  
      var data = [DataModel]()
  
      override func viewDidLoad() {
          collectionView.delegate = self
          collectionView.dataSource = self
          collectionView.register(UINib(nibName: "MyCell", bundle: nil), forCellWithReuseIdentifier: "MyCell")
          getData()
      }
  
      func getData() {
          someAsyncMethodToGetData() { (data) in
              // Using CloudKit so I think this is necessary, but tried it with and without
              DispatchQueue.main.async {
                  self.data = data
                  self.collectionView.reloadData()
                  // This is the only way to get cells to render and for cellForItemAt to be called after data is loaded
                  self.collectionView.reloadData()
              }
          }
  
      // Gets called initially AND after reloadData is called in the data completion closure. First time is 0, next time is number of DataModel objects
      func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -&gt; Int {
          return data.count
      }
  
      // Only gets called initially (unless I call reloadData() twice)
      func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -&gt; UICollectionViewCell {
          guard let cell = feedCollectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath) as? MyCell else {
              return UICollectionViewCell()
          }
  
          // Configure the cell with data...
  
          return cell
      }
  }
  </code></pre>
  
  <p>So here are some things I've already tried:</p>
  
  <ul>
  <li>Made double sure <code>reloadData()</code> is being called on the main thread (added a symbolic breakpoint and called <code>Thread.isMainThread</code> to verify)</li>
  <li>Moved <code>reloadData()</code> into a button action to eliminate the possibility of any thread issues - still had to click the button twice to get cells to show up</li>
  <li>Put the updates in <code>performBatchUpdates</code> based on some other SO solutions I came across</li>
  <li>Added <code>setNeedsLayout</code> and <code>setNeedsDisplay</code> (not sure why this would be necessary in this case, but I did try it out of desperation.</li>
  </ul>
  
  <p>Any suggestions? </p>
  
  <h1>Update 1</h1>
  
  <p>Ok, think I found the issue, but I'd like to understand the best way to solve. It appears by calling <code>reloadData</code>, the collection view will only reload cells already visible. I hacked the code above a bit to return 1 cell before <code>getData()</code> is called. When <code>getData()</code> then calls <code>reloadData()</code> that 1 cell gets updated (but if there are 10 items in the data array, it will still only [re]display the 1 cell). I suppose this makes sense, as <code>reloadData()</code> only reloads visible cells, but this has to be a common issue when the length of the array changes and there is still room on the screen to display. Also, why does calling <code>reloadData()</code> twice solve the issue and display cells that were never visible? </p>
  
  <p><a href="https://gist.github.com/derrickshowers/b98c3a7b092f7dc70decf2cf042f2407" rel="noreferrer">Here</a> is an even simpler version of the code I have above, removing the whole "get data from a server" idea and replacing with a simple delay.</p>