Home > Mobile >  I can not change the value with .onAppear(), .onTapGesture() function and with a NavigationLink in S
I can not change the value with .onAppear(), .onTapGesture() function and with a NavigationLink in S

Time:12-17

I am stuck with little problem , I can not change the value with .onAppear(), .onTapGesture() function and with a NavigationLink in SwiftUI

If anyone can tell me how to solve it ? Regards,

VIEW ONE

struct ContentView: View {
    @StateObject var vm = ViewModel()
    var body: some View {
        NavigationView{
        List{
        ForEach(0..<4){ numero in
           NavigationLink(
       
            destination: DetailView().onAppear(){
//This function is not working 
                vm.takeNumber(number: numero)
            },
            label: {
                Text(String(numero))
            })
 
        }
    }
    }
    }    
}
class ViewModel: ObservableObject {
    @Published var numero:Int = 0    
    func takeNumber(number: Int) {
        numero = number
    }
}

VIEW TWO

struct DetailView: View {
    @StateObject var vm = ViewModel()
    var body: some View {
// My number is not updated 
        Text(String("My NUMBER : \(vm.numero)"))
    }
}

CodePudding user response:

@StateObject creates a fresh copy of your model.

Try changing it to

@ObservedObject var model: ViewModel

in DetailView and pass it as argument in ContentView.

Good read: https://www.hackingwithswift.com/quick-start/swiftui/whats-the-difference-between-observedobject-state-and-environmentobject

CodePudding user response:

It looks like your approach is a bit incorrect. You are creating a new instance of your ViewModel within each view. To correctly pass the StateObject's instance forward, you will need to set it as an ObservedObject in your DetailView. StateObject should be your source of truth for this view model. I suggest reading up on the fundamentals of these property wrappers.

For this code to work, the onAppear should live within your DetailView. Within the detail view, call your takeNumber function with your number passed from your for loop. Then, reference your published value in your detail view. Viola!

struct ContentView: View {
@StateObject var vm = ViewModel()
var body: some View {
    NavigationView{
        List{
            ForEach(0..<4){ numero in
                NavigationLink(
                    destination: DetailView(vm: vm, number: numero),
                    label: {
                        Text(String(numero))
                    })
               }
          }
      }
  }
}

struct DetailView: View {
// Updated to observed object
// note how we are not constructing a new object here
    @ObservedObject var vm: ViewModel
// Passing our number forward from our loop written in contentview
    let number: Int
    var body: some View {
        // My number is not updated
        Text(String("My NUMBER : \(vm.numero)"))
            .onAppear {
                vm.takeNumber(number: number)
            }
    }
}

class ViewModel: ObservableObject {
    @Published var numero:Int = 0
    func takeNumber(number: Int) {
        numero = number
    }
}
  • Related