Mary Doe
Mary Doe

Reputation: 1323

Updating the Collection Stored in EnvironmentObject in SwiftUI

I am following a question posted on StackOverFlow about updating a collection stored in EnvironmentObject. The idea is that AppState stores an array of tweets. I want to update the tweet by changing their like status. I created a byId function, which returns the tweet using their id and then I change it. But this does not change the tweets stored in the EnvironmentObject array. If I refer to the tweet by index then it works.

Why is that?

class AppState: ObservableObject {
    
    @Published var tweets: [Tweet] = [Tweet(text: "Tweet 1", like: false), Tweet(text: "Tweet 2", like: false)]
    
    func byId(_ id: UUID) -> Tweet? {
        tweets.first { $0.id == id }
    }
    
}

struct Tweet: Identifiable, Hashable {
    let text: String
    var like: Bool
    let id = UUID()
}

struct ContentView: View {
    
    @EnvironmentObject var appState: AppState
    
    var body: some View {
        List(appState.tweets) { tweet in
            TweetCellView(tweet: tweet, onLiked: {
                
                guard var tweetToEdit = appState.byId(tweet.id) else {
                    return
                }
                
                tweetToEdit.like.toggle() // this does not work
                
                appState.tweets[0].like.toggle() // this works 
            })
        }
    }
}

Upvotes: 1

Views: 33

Answers (1)

Asperi
Asperi

Reputation: 258057

Why is that?

Because Tweet is a struct, ie. is-a value type, ie. byId returns a copy of value in view model, so modifying a copy does nothing with original view model, so nothing in view model is updated, so view is not updated.

Thus, yes, the solution is to find an index of tapped tweet in view model published array and modify it exactly in-place that modifies a property (because array is also value-type) that generates update event that will be handed by ObservedObject wrapper, which is dynamic property, so generates refresh view.

Something like that. The End :)

Upvotes: 1

Related Questions