struct MakeVideo: View {
@EnvironmentObject var modelData: ModelData
@State private var chosenFriends: [FriendModel] = []
mutating func addFriend(_friend: FriendModel) -> Void {
chosenFriends.append(_friend)
}
var body: some View {
VStack {
ForEach(modelData.friends) { friend in
HStack {
ProfilePic(picture: friend.profilepic!)
Text("@" friend.username!)
//TODO: This is updating the val, it just isn't being shown here
Button("Add", action: friend.toggleChosen)
if friend.isChosen {
Image(systemName: "star.fill")
.foregroundColor(.yellow)
} else {
Image(systemName: "star")
}
}
}
}
}
}
struct MakeVideo_Previews: PreviewProvider {
static var previews: some View {
MakeVideo()
.environmentObject(ModelData())
}
}
I am trying to dynamically update this so that when ai click the Button, it'll make the star be filled instead of empty. In the debugger I see the class value being changed however the change does not appear in the view. I also made the var in the class @Published, which I thought would allow the view to change with the value
CodePudding user response:
try using this:
ForEach($modelData.friends) { $friend in // <-- here $
CodePudding user response:
You don't say that you get a compiler error on the following line:
Button("Add", action: friend.toggleChosen)
Therefore I deduce that FriendModel
is a class
, not a struct
. If FriendModel
were a struct
and toggleChosen
were a mutating
method, then you would get an error: “Cannot use mutating member on immutable value”.
Even if FriendModel
conforms to ObservableObject
, the problem is that ObservableObject
s do not automatically compose. A change to an @Published
property of a FriendModel
will not be noticed by a containing ModelData
, which means (in this case) that SwiftUI will not notice that friend.isChosen
was modified.
I suggest making FriendModel
into a struct
.
I also recommend using Point-Free's Composable Architecture package (or something similar) as your app architecture, because it provides a comprehensive solution to problems like this.
CodePudding user response:
Body is only called for states that are used. Since chosenFriends is not used in body, it is not called when it is changed in a button action.
To fix, write a func isFriend and lookup the friend ID in the chosenFriends array and use the result of that in body to show the star. Since chosenFriends is now used, body will be called. Also change the button to call the addFriend func which would be better named as chooseFriend by the way.