cyberpirate92
cyberpirate92

Reputation: 3176

How to publish changes to a single object in a object array

I have the following classes

class ListItem: Identifiable {
    var id: UUID
    var name: String
    var description: String
    var isFavorite: Bool

    var debugDescription: String {
        return "Name: \(self.name) | Favorite?: \(self.isFavorite)"
    }

    public init(name: String) {
        self.name = name
        id = UUID()
        self.description = "Some text describing why \(self.name.lowercased()) is awesome"
        self.isFavorite = false
    }
}


class ListItems: ObservableObject {
    @Published var items: [ListItem]

    let defaultAnimals = ["Ant", "Bear", "Cat", "Dog", "Elephant", 
          "Fish", "Giraffe", "Hyena", "Iguana", "Jackal", "Kingfisher", "Leopard", "Monkey"]

    public init(animals: [String] = []) {
        let animalList: [String] = animals.count > 0 ? animals : defaultAnimals
        self.items = animalList.sorted {
            $0.lowercased() < $1.lowercased()
        }.map {
            ListItem(name: $0.firstUppercased)
        }
    }
}

and the following image view in ContentView

struct ContentView: View {
    @ObservedObject var list: ListItems = ListItems()
    var body: some View {
        List(list.items) {
            animal in HStack {
                // ...
                Image(systemName: animal.isFavorite ? "heart.fill" : "heart").foregroundColor(.pink).onTapGesture {
                    let index = self.list.items.firstIndex { $0.id == animal.id } ?? -1
                    if (index >= 0) {
                        self.list.items[index].isFavorite = !animal.isFavorite
                        self.list.items = Array(self.list.items[0...self.list.items.count-1]) // <--
                    }
                }
                // ...
            }
        }
    }
}

Everytime, the image view is tapped, I am basically reassigning the entire array like this so that the changes can be reflected in the UI

self.list.items = Array(self.list.items[0...self.list.items.count-1])

My question: How can I refactor my code to prevent reassigning the entire object array every time some object property changes?

I am fairly new to Swift & iOS development, not sure if I am missing something basic.

Upvotes: 0

Views: 491

Answers (1)

zgluis
zgluis

Reputation: 3375

Declare ListItem as an struct instead of a class, this way the view will be notified when isFavorite changes. And just a little suggestion; you can use toggle to change the value of a boolean: self.list.items[index].isFavorite.toggle()

Upvotes: 1

Related Questions