GO FURTHER, FASTER: Try the Swift Career Accelerator today! >>

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 try! Swift Tokyo.

SPONSORED Ready to dive into the world of Swift? try! Swift Tokyo is the premier iOS developer conference will be happened in April 9th-11th, where you can learn from industry experts, connect with fellow developers, and explore the latest in Swift and iOS development. Don’t miss out on this opportunity to level up your skills and be part of the Swift community!

Get your ticket here

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

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

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.