1

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!

SRMR
  • 3,064
  • 6
  • 31
  • 59
  • If your want or expect your array to be unique, then just use a set instead of an array. That way you will not get duplicate data. See the post (http://stackoverflow.com/questions/27624331/unique-values-of-array-in-swift). – Erion S Dec 18 '16 at 17:06
  • @ErionV yeah good info, I was actually thinking I might end up trying a Set, but wasn't sure if I was messing up something simpler in what I had so far also. Thanks tho for reiterating the possibility of trying a set! – SRMR Dec 18 '16 at 17:15

1 Answers1

1

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.

JustinM
  • 2,202
  • 2
  • 14
  • 24
  • looks nice, lets wait for OP's response. – Bista Dec 19 '16 at 06:17
  • This didn't work for me, but it looks much more elegant than mine so I'll definitely swap out my `for` loops and etc for what you suggest. I think I might need to empty out the the array that gets passed to me in the `(game: [Game])` part or something, because it might not be emptying that part out or something. Not sure if that makes sense but I'm going to try it out – SRMR Dec 20 '16 at 01:05
  • The issue shouldn't be coming from this function so if you need more help just post some more of your code and I'll take a look. – JustinM Dec 20 '16 at 01:31
  • Thanks for taking me to a more swifty version of my code. As I'm refactoring, is there any reason `var updatedColorArray = [String]()` + `game.forEach { updatedColorArray.append($0.teamColor) }` + `unwrappedSelf.teamColorArray = updatedColorArray` couldn't be simplified into `game.forEach { unwrappedSelf.teamColorArray.append($0.teamColor) }`? When I try it, it goes back to the doubling sort of thing, and I'm not sure if it has to do with the `[weak self]` stuff or what exactly, but I'm sure I'm missing something. Any ideas? – SRMR Jan 28 '17 at 16:52
  • To simplify your code you may not even want to get the color but just make an array of games. Then in tableView.cellForRow, assign the teamColor from the gameObject. Then in the closure just set your game array to new game array. Should be quicker because you don't need to iterate over every game object in the closure to get the teamColor property – JustinM Jan 28 '17 at 20:18