UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

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 Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

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.