I have 1 CollectionView called animalCollectionView
that populates with over 100 AnimalModel objects from an AnimalData struct. Below the CollectionView, I have 4 buttons with different Animal classifications: Fish, Amphibian, Bird, Reptile. I would like these 4 buttons to toggle the appropriate data in the CollectionView. Each AnimalModel object has a property called animalSelected that should toggle accordingly.
Progress-wise, I am almost there. I am just having trouble iterating through ALL of the data to change the animalSelected property on the appropriate objects.
Here is the data:
struct AnimalModel {
var animalName:String
var animalClassification:Animal
var animalSelected:Bool
enum Animal:String {
case bird
case fish
case reptile
case amphibian
}
}
struct AnimalData {
static func allAnimal() -> [AnimalModel] {
return [
AnimalModel(animalName: "Salmon", animalClassification: .fish, animalSelected: false),
AnimalModel(animalName: "Goldfish", animalClassification: .fish, animalSelected: false),
AnimalModel(animalName: "Guppy", animalClassification: .fish, animalSelected: false),
AnimalModel(animalName: "Shark", animalClassification: .fish, animalSelected: false),
AnimalModel(animalName: "Tuna", animalClassification: .fish, animalSelected: false),
AnimalModel(animalName: "Clownfish", animalClassification: .fish, animalSelected: false),
AnimalModel(animalName: "Swordfish", animalClassification: .fish, animalSelected: false),
AnimalModel(animalName: "Frog", animalClassification: .amphibian, animalSelected: false),
AnimalModel(animalName: "Toad", animalClassification: .amphibian, animalSelected: false),
AnimalModel(animalName: "Newt", animalClassification: .amphibian, animalSelected: false),
AnimalModel(animalName: "Salamander", animalClassification: .amphibian, animalSelected: false),
AnimalModel(animalName: "Ostrich", animalClassification: .bird, animalSelected: false),
AnimalModel(animalName: "Peacock", animalClassification: .bird, animalSelected: false),
AnimalModel(animalName: "Eagle", animalClassification: .bird, animalSelected: false),
AnimalModel(animalName: "Duck", animalClassification: .bird, animalSelected: false),
AnimalModel(animalName: "Chicken", animalClassification: .bird, animalSelected: false),
AnimalModel(animalName: "Snake", animalClassification: .reptile, animalSelected: false),
AnimalModel(animalName: "Chameleon", animalClassification: .reptile, animalSelected: false),
AnimalModel(animalName: "Lizard", animalClassification: .reptile, animalSelected: false),
AnimalModel(animalName: "Turtle", animalClassification: .reptile, animalSelected: false)
// + about 80 more...
]
}
}
Here is the VC
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
@IBOutlet weak var animalCollectionView: UICollectionView!
@IBOutlet weak var birdOutlet: UIButton!
@IBOutlet weak var fishOutlet: UIButton!
@IBOutlet weak var reptileOutlet: UIButton!
@IBOutlet weak var amphibion: UIButton!
var all = AnimalData.allAnimal()
override func viewDidLoad() {
super.viewDidLoad()
animalCollectionView.delegate = self
animalCollectionView.dataSource = self
}
@IBAction func birdBtnPressed(_ sender: UIButton) {
// for bird in all {
// bird.animalSelected = true
// }
all[1].animalSelected = true
animalCollectionView.reloadData()
}
@IBAction func fishBtnPressed(_ sender: UIButton) {
}
@IBAction func reptileBtnPressed(_ sender: UIButton) {
}
@IBAction func amphibionBtnPressed(_ sender: UIButton) {
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return all.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ANIMAL", for: indexPath) as! AnimalCollectionViewCell
cell.animalNameLabel.text = all[indexPath.item].animalName
cell.animalClassificationLabel.text = all[indexPath.item].animalClassification.rawValue
if all[indexPath.item].animalSelected {
cell.alpha = 1
} else {
cell.alpha = 0.2
}
return cell
}
}
birdButtonPressed is where I was making the attempt.. I have commented out:
for bird in all {
bird.animalSelected = true
}
because that gives the error: Cannot assign to property: 'bird' is a 'let' constant
all[1].animalSelected = true
obviously does not iterate over the birds, but I was just doing this to ensure the second cells alpha changed... which it did! (see the screenshot below)
How can I iterate over the data to change animalSelected
to true
on the appropriate cells?
I would first start by pulling the Animal enum out of your AnimalModel struct for modularity. It also allows for better checking using the enum cases for equality.
There are two things that you must do to get your value to change. Because you are using a struct, a value type instead of a reference type, you must provide a way to change its internal value. You achieve this by adding a mutating func as follows:
struct AnimalModel {
var animalName: String
var animalClassification: Animal
var animalSelected: Bool
mutating func setAnimalToSelected(value: Bool) {
animalSelected = value
}
}
The mutating func allows you to change the value inside of a struct.
But before doing that you must obtain the specific index of it and change that specific struct with the mutating func.
for (index, animal) in all.enumerated() {
if animal.animalClassification == Animal.bird {
all[index].animalSelected = true
//if you only have one section
let indexPath = IndexPath(row: index, section: 0)
self.collectionView.reloadItems(at: [indexPath])
}
}