TEAM LICENSES: Save money and learn new skills through a Hacking with Swift+ team license >>

Updating @State variable, view not updating

Forums > SwiftUI

My app allows users to set four dates that get used in various parts of the app. I've created a class that stores these dates in UserDefaults. I'm using the @Environment property wrapper to use this in various views of my app.

In a settings view, I want to give the ability to change these dates. The code to actually update the dates works fine, but I can't get the DatePicker to be "preset" to the current values saved in the Environment variable.

When I try to set the State variable when it's declared, I get this error "Cannot use instance member 'pipeline' within property initializer; property initializers run before 'self' is available". This make sense, as the @Environment var isn't avialable to use yet.

Next I tried using .onAppear(). This sets the @State variables correctly, but the view isnt' refreshing, so the datepickers do not change.

import SwiftUI

struct PipelineView: View {

    @Environment(Pipeline.self) private var pipeline

    @State private var newQ1: Date = .now
    @State private var newQ2: Date = .now
    @State private var newQ3: Date = .now
    @State private var newQ4: Date = .now

    var body: some View {
        VStack {
            Form {
                DatePicker("Q1", selection: $newQ1, displayedComponents: .date)
                DatePicker("Q2", selection: $newQ2, displayedComponents: .date)
                DatePicker("Q3", selection: $newQ3, displayedComponents: .date)
                DatePicker("Q4", selection: $newQ4, displayedComponents: .date)
                Button {
                    pipeline.setQuarterDates(q1: newQ1, q2: newQ2, q3: newQ3, q4: newQ4)
                } label: {
                    Text("Save")
                }
            }
        }
        .onAppear() {
            newQ1 = pipeline.getQ1()
            newQ2 = pipeline.getQ2()
            newQ3 = pipeline.getQ3()
            newQ4 = pipeline.getQ4()
            print(newQ1.formatted()) //testing to make sure the date is actually updated, it is.
        }
    }
}

2      

@tbaj  

Apparently this is an ongoing issue with DatePicker. There used to be similar problems with TextField.

It seems that DatePicker misses an update cycle or something like that. .onAppear is either too late or too early for DatePicker to react to the change.

You can easily reproduce this with the following (iOS 17.2):

struct ContentView: View {
  @State private var date = Date()
  @State private var toggle = false

  var body: some View {
    VStack {
      Form {
        DatePicker("Date", selection: $date)
        Toggle("Refresh", isOn: $toggle) // this will cause the view to redraw and DatePicker to refresh itself
      }
    }
    .onAppear {
      date = .distantPast
    }
  }
}

To fix this, you can either wrap the code inside .onAppear with Task . Or simply replace .onAppear with .task.

2      

Hacking with Swift is sponsored by RevenueCat.

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.