Home > other >  View disappears when using Toggle()-button in SwiftUI
View disappears when using Toggle()-button in SwiftUI

Time:07-03

I have a problem in the following code, that whenever I use the Toggle()-Button the SettingsEx1View disappears and the Exercise1View() appears. They are connected with the ObservableObject Profile(). I get this error when starting the app, but it seems that is a bug with SwiftUI Apple has to fix. The weird thing is, that when I delete line 18 and 19

    let osc = DynamicOscillator()
    let audioEngine = AudioEngine()

it works perfectly fine. Is there something I have overlooked or do you know anything I could do? Any help is appreciated, thanks!!

import SwiftUI
import AVFoundation
import AudioKit
import SoundpipeAudioKit
import Foundation

class Profile: ObservableObject {
    
    @Published var playSoundeffects = true
    @Published var waveformIndex = 0

}

struct Exercise1View: View {
    
    @EnvironmentObject var profile: Profile
        
    let osc = DynamicOscillator()
    let audioEngine = AudioEngine()
    
    var body: some View {
        NavigationLink(
            destination: SettingsEx1View())
        {
            Image(systemName: "gearshape.circle")
        }
            .navigationTitle("Exercise1")
    }
}

struct SettingsEx1View: View {
    
    @EnvironmentObject var profile: Profile
    let waveformOptions = ["sine", "triangle", "sawtooth", "square"]
    
    var body: some View {
            Form {
                Section(header: Text("General")) {
                    Toggle("play soundeffects", isOn: $profile.playSoundeffects)
                    Picker("waveform", selection: $profile.waveformIndex) {
                        ForEach(0 ..< waveformOptions.count) {
                            Text(self.waveformOptions[$0])
                        }
                    }
                }
            }
            .navigationTitle("Settings")
    }
}

struct HomeScreen: View {
    
    @EnvironmentObject var profile: Profile
    @AppStorage("playSoundeffects") var playSoundeffectsSave: Bool = true
    @AppStorage("waveform") var waveformIndexSave: Int = 0
    
    var body: some View {
        NavigationView{
                NavigationLink(destination: Exercise1View())
                {Text("Exercise1")}
        }
        .onAppear {
            profile.playSoundeffects = playSoundeffectsSave
            profile.waveformIndex = waveformIndexSave
        }
        .onChange(of: profile.playSoundeffects) { newValue in
            playSoundeffectsSave = profile.playSoundeffects
        }
        .onChange(of: profile.waveformIndex) { newValue in
            waveformIndexSave = profile.waveformIndex
        }
    }
}

struct ContentView: View {
    var body: some View {
        HomeScreen()
            .environmentObject(Profile())
    }
}

CodePudding user response:

The HomeScreen.body depends on Profile settings, so when latter updated it is refreshed and NavigationView is recreated as part of body, so its navigation stack destroyed.

As NavigationView does not depend on Profile itself a simplest solution is to separate it into stand-alone view, like

struct HomeScreen: View {
    
    // ... other code
    
    var body: some View {
      MainView()
        .onAppear {
            profile.playSoundeffects = playSoundeffectsSave

    // ... other code
}

struct MainView: View {
  var body: some View {
        NavigationView{       // << here !!
                NavigationLink(destination: Exercise1View())
                {Text("Exercise1")}
        }
  }
}

See also this for more info: https://stackoverflow.com/a/72824345/12299030

  • Related