0

I have a UICollectionView with 16 cells. 1 of the cells (the Game Over cell) must be random. I would like to randomize the Game Over cell in the collection view.

I have it somewhat working by using different sections, but that defeats the purpose of visually blending in with the 16.

I also had it somewhat working by creating an array of strings, one of the strings being "GameOver" - and then I did a shuffle on the array to customize how this cell appears.

That also didn't work, because it did not give me IB control of the game over cell.

How can I use the storyboard by creating 2 prototype cell identifiers, to randomize 1 of the game over cells, and 15 normal cells on a collection view of 16 total cells?

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Joe
  • 3,772
  • 3
  • 33
  • 64

1 Answers1

2

Here's one fairly simple approach:

In your view controller, define a property to hold any array of cell reuse identifiers that can be referenced later. You can set an initial, non-random configuration, like this:

var reuseIdentifiers = ["GameOver", "Normal", "Normal", "Normal", "Normal", "Normal", "Normal", "Normal", "Normal", "Normal", "Normal", "Normal", "Normal", "Normal", "Normal", "Normal"]

Define the following method, and call it sometime during the initialization of your view controller, before the collectionView is shown on screen, and before each time the collection view data is reloaded:

func randomizeReuseIdentifiers() {
    var randomized = [String]()

    for _ in initialIdentifiers {
        let random = reuseIdentifiers.removeAtIndex(Int(arc4random_uniform(UInt32(reuseIdentifiers.count))))
        randomized.append(random)
    }

    reuseIdentifiers = randomized
}

And then in your collectionView(cellForItemAtIndexPath:NSIndexPath) method, look up the matching reuseIdentifier for the current indexPath, like this:

func collectionView(_ collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let identifier = reuseIdentifiers[indexPath.item]
    return collectionView.dequeueReusableCellWithReuseIdentifier(identifier, forIndexPath: indexPath)
}

This approach also has the benefit of allowing you to add additional identifiers into the initial reuseIdentifiers array in the future, to include other types of cells in one or more random locations.

Daniel Hall
  • 13,457
  • 4
  • 41
  • 37
  • That worked! I didn't even think of using an array of reusable identifiers in the cellForItemAtIndexPath method. A bit out of scope of my initial question... if I wanted to put GameOver and Normal in their own arrays (2 arrays), would that be feasible with your answer? Idea here is I'd like the "Normal" cells to disable after tapped, while always keeping a GameOver on screen. If they're all in the same Array, there's a chance I can disable the GameOver cell, which I don't want. Again... out of scope, just requesting your input. – Joe Apr 22 '16 at 20:06
  • @Joe It's possible but significantly more complex to use two arrays. There are easier ways you could make it work with one array. For example, you could add an `isGameOver` property to the view controller and then add the following line after dequeuing the cell, but before returning it: `cell.userInteractionEnabled = isGameOver ? identifier == "GameOver" : true`. This basically says "if the game is over, user interaction is only enabled for this cell if the identifier for this index is equal to 'GameOver'. If the game is not over, then user interaction is always enabled for this cell" – Daniel Hall Apr 22 '16 at 20:23
  • I actually might have figured it out with 2 arrays. I seperated GameOver and Normal into their own arrays. Then in randomizeReuseIdentifiers, I just set initialIdentifiers as gameOverArray + contintinueArray. However I do like your idea of the ternary operator and disabling interaction. This could come in handy... Thanks for your help!!! – Joe Apr 22 '16 at 20:33