BLACK FRIDAY: Save 50% on all my Swift books and bundles! >>

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      

Save 50% in my WWDC sale.

SAVE 50% All our books and bundles are half price for Black Friday, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

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.