Table Refresh doubles number of Array items

86 views Asked by At

I have static data (3 values) coming from CloudKit, and the problem is when I refresh the UITableView, I get 6 values instead of 3 values.

I'm not sure why it doesn't refresh and throw out old data from the Array, but instead it keeps the old data and adds the same data to it Array.

Initial UITableView set up:

func getData() {
    cloud.getCloudKit { (game: [Game]) in
        var teamColorArray = [String]()
        for item in game {
            let itemColor = item.teamColor
            teamColorArray.append(itemColor)
            print("TCA in: \(teamColorArray)")
        }

        self.teamColorArray = teamColorArray
        self.tableView.reloadData()
    }
}

Prints: ["CC0033", "FDB927", "E3263A"]

Refresh data when UIRefreshControl pulled:

@IBAction func refreshData(_ sender: Any) {
    self.teamColorArray.removeAll()
    getData()
    self.refreshControl?.endRefreshing()
}

Prints: ["CC0033", "FDB927", "E3263A", "CC0033", "FDB927", "E3263A"]

I think I have it narrowed down to somehow game in the function getData() is incremented to a count of 6 items. I'm not sure why it wouldn't always stay at 3 items if it were pulling all new data from CloudKit, but maybe I'm not understanding that calling a completion handler doubles the values and maybe I need to removeAll inside of that? I'm just really not sure

Does anyone have anything they see I'm doing wrong, or anything they'd do to fix my code?

Thanks!

1

There are 1 answers

5
JustinM On BEST ANSWER

Might have to do with your async call to cloudkit. I'm not too familiar with refresh control but here is a way to maybe solve your problem and also make your code a little cleaner.

func getData(_ completion: () -> ()) {
  teamColorArray.removeAll()
  cloud.getCloudKit { [weak self] (game: [Game]) in
    guard let unwrappedSelf = self else { return }
    var updatedColorArray = [String]()
    game.forEach { updatedColorArray.append($0.teamColor) }
    unwrappedSelf.teamColorArray = updatedColorArray
    completion()
 }
}

now when you call getData it would look like this

getData { 
   DispatchQueue.main.async { [weak self] in
     self?.tableView.reloadData()
     self?.refreshControl?.endRefreshing()
  }
}
  • you add weak self to remove the possibility of retain cycles

  • make sure your updating UI from the main thread

  • Call reloadData and endRefreshing when you know the array has been set properly

I put teamColorArray.removeAll() inside the getData function since it seems like you will need to call it everytime and it saves you from having to add it before the function everytime.