1
votes

When testing on a real device, I get the Modifying state during view update, this will cause undefined behavior issue for the code below. Tested on an iPhone 11. On the simulator, the issue doesn't arise and the code works as expected.

From what I can gather, modifying state from inside .onAppear is fine.

What's going on here? Why am I getting this error?

struct Clouds: View {
    @State private var cloudOffset: CGFloat = 0.0
    @State private var cloudOffset2: CGFloat = 0.0

    @EnvironmentObject var mainData: MainData
    
    var body: some View {
        GeometryReader { geo in
            if mainData.animateClouds {
                Image("cloudsBlurry")
                    .resizable()
                    .scaledToFit()
                    .offset(x: self.cloudOffset, y: 0.0)
                    .onAppear {
                        let baseAnimation = Animation.linear(duration: 30)
                        let repeated = baseAnimation.repeatForever(autoreverses: true)

                        withAnimation(repeated) {
                            self.cloudOffset += geo.size.width * 0.50 //Error here
                        }
                    }
                Image("cloudsBlurry3")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(height: geo.size.height * 2)
                    .offset(x: self.cloudOffset2, y: 0.0)
                    .onAppear {
                        let baseAnimation = Animation.linear(duration: 30)
                        let repeated = baseAnimation.repeatForever(autoreverses: true)
                        
                        self.cloudOffset2 = -geo.size.width //Error here
                        
                        withAnimation(repeated) {
                            self.cloudOffset2 += geo.size.width * 0.50 //Error here
                        }
                    }
            } else {
                Image("cloudsBlurry")
                    .resizable()
                    .scaledToFit()
                    .offset(x: 0.0, y: 0.0)
            }
        }
    }
}
1

1 Answers

0
votes

You have cycle, because offset(x: self.cloudOffset dependency and self.cloudOffset += geo force refresh due to above dependency.

Try to make update with a bit delay, to give current refresh to finish with current offset value:

withAnimation(repeated) {
    DispatchQueue.main.async {
       self.cloudOffset += geo.size.width * 0.50
    }
}