Reputation: 1323
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
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