ReyHaynes
ReyHaynes

Reputation: 3092

Variable assignment with mutating functionality

So I'm fairly new to SwiftUI & Swift (Javascript background) and I am going through the SwiftUI tutorial on Apple website.

When you get through the first section, you'll end up with LandmarkDetail.swift body ends up something like this:

var body: some View {
    VStack {
        MapView(coordinate: landmark.locationCoordinate)
            .edgesIgnoringSafeArea(.top)
            .frame(height: 300)

        CircleImage(image: landmark.image)
            .offset(x: 0, y: -130)
            .padding(.bottom, -130)

        VStack(alignment: .leading) {
            HStack {
                Text(landmark.name)
                    .font(.title)
                
                Button(action: {
                    self.userData.landmarks[self.landmarkIndex].isFavorite.toggle()
                }, label: {
                    if (self.userData.landmarks[self.landmarkIndex].isFavorite) {
                        Image(systemName: "star.fill")
                            .foregroundColor(.yellow)
                    }
                    else {
                        Image(systemName: "star")
                            .foregroundColor(.gray)
                    }
                })
            }

            HStack(alignment: .top) {
                Text(landmark.park)
                    .font(.subheadline)
                Spacer()
                Text(landmark.state)
                    .font(.subheadline)
            }
        }
        .padding()

        Spacer()
    }
    .navigationBarTitle(Text(landmark.name), displayMode: .inline)
}

All good. So I decide to make some small incremental changes just to test the language. I noticed self.userData.landmarks[self.landmarkIndex] is used twice so I simply added that as a variable within the body and had the view return explicitly.

var userDataLandmark: Landmark = self.userData.landmarks[self.landmarkIndex]

return VStack {

No big deal. Then I replaced the repeating landmark:

Button(action: {
     userDataLandmark.isFavorite.toggle()
}, label: {
     if (userDataLandmark.isFavorite) {
         Image(systemName: "star.fill")

Everything looked fine on the surface, but the toggle() functionality no longer works. Generally assuming this is some referencing/pointer stuff but If anyone could explain why that'd be great.

Upvotes: 0

Views: 59

Answers (1)

New Dev
New Dev

Reputation: 49590

When you did:

var userDataLandmark: Landmark = self.userData.landmarks[self.landmarkIndex]

you created a copy of self.userData.landmarks[self.landmarkIndex], because Landmark is a value-type (a struct).

Now, when you do:

userDataLandmark.isFavorite.toggle()

you're toggling the copy. So, it doesn't change the .landmarks property of the observed environment variable userData, which is what would have caused the view's body to be recomputed.

Upvotes: 3

Related Questions