NavigationStack Fatal error: ‘try!

I am struggling to get pickers work in a form. I add NavigationStack and get this error Fatal error: 'try!' expression unexpectedly raised an error: SwiftUI.AnyNavigationPath.Error.comparisonTypeMismatch

I have tried most every format or picker setup as well as DatePicker and can’t seem to determine how to get the selected item in a picker list saved.

running: Xcode 16.1

import SwiftUI import SwiftData

struct RoundsEditView: View { @Bindable var roundsdata: RoundsData @Environment(.modelContext) private var modelContext // @Environment(.dismiss) var dismiss

@State private var playDate = Date.now

@State private var selectedTee = "Gold"
let tees = ["Black", "Blue", "White", "Gold", "Red", "Silver"]

@Query(sort: \PlayerData.playerHandle) private var players: [PlayerData]
@State private var selectedHandle: PlayerData? = nil

var body: some View {
    NavigationStack {
        Form {
            HStack {
                Text("Course:")
                TextField("Course Name", text: $roundsdata.roundscourseName)
                    .textContentType(.name)
            }
            
            HStack {
                //                 DatePicker("Date:", selection: $playDate, in: ...Date(),
                DatePicker("Date:", selection: $playDate,
                           displayedComponents: [.date])
                
                //      DatePicker("Date:", selection: $playDate, in: ...Date(),
                //                 displayedComponents: .date).onChange(of: playDate) { oldState, newState in model.youDidChangeMethod(from: oldState, to: newState)
            }
            
            Section {
                Picker("Handle:", selection: $selectedHandle) {
                    Text("Select a Handle").tag(nil as PlayerData?)
                    ForEach(players, id: \.self) { player in
                        HStack {
                            Text(player.playerHandle)
                                .frame(maxWidth: .infinity, alignment: .leading)
                                .tag(player as PlayerData?)
                        }
                        .frame(maxWidth: .infinity, alignment: .leading)
                        .tag(player as PlayerData?)
                    }
                }
                //         .pickerStyle(.inline)  this does not fix issue or design wise work
            }
            
            //       HStack {
            //           Text("Tee:")
            //           TextField("Tee", text: $roundsdata.roundsTee)
            //               .textContentType(.name)
            //       }
            
            HStack {
                Picker("Tee:", selection: $selectedTee) {
                    ForEach(tees, id: \.self) {
                        Text($0)
                    }
                }
            }
            
            HStack {
                Text("Handicap:")
                TextField("Handicap", value: $roundsdata.roundsHandicap, format: .number)
                    .textContentType(.name)
            }
            HStack {
                Text("*****:")
                TextField("*****", value: $roundsdata.roundsGross, format: .number)
            }
            HStack {
                Text("Net:")
                TextField("Net", value: $roundsdata.roundsNet, format: .number)
                    .textContentType(.name)
            }
            HStack {
                Text("Rating:")
                TextField("Rating", value: $roundsdata.roundsRating, format: .number)
                    .textContentType(.name)
            }
            HStack {
                Text("Slope:")
                TextField("Slope", value: $roundsdata.roundsSlope, format: .number)
                    .textContentType(.name)
            }
        }
        .navigationTitle("Edit Rounds")
    }
}

}

Answered by Gyannes in 815999022

Apple developer indicates it had been deprecated For iOS versions 17.0

https://developer.apple.com/documentation/swiftui/view/onchange(of:perform:)

in any case I still get errors with the picker code. I will search for the answer.

thank you for your input.

It's quite clear that your code formatting didn't work properly when you posted this, so you should've immediately revised it and corrected it. Basically, put three backticks on one line, then all of your code, then another line with just three backticks on it. It's not difficult, and it would help us when reading it.

You've put a bunch of commented code in there. Is it relevant to your issue?

You don't say what line causes the error?

Why does this need to be embedded in a NavigationStack anyway?

Why do you need an HStack around one DatePicker?

At your ForEach(players, id: \.self) { player in line, you have an HStack and a Text with some modifiers (.frame and .tag). Why have you put this in an HStack and then put the same modifiers on the HStack?

Are the five HStacks at the bottom relevant to the issue?

I'm not entirely sure you understand how HStacks work. They place items horizontally. If there's only one item, does it need to be in an HStack?

Please clean up this question and we may be able to help you. In doing so you might actually fix the issue yourself...

I will try to clean out some of the commented text. I have it in there as reference for me as I trying to resolve the issue and not replicate something already tried. But I will take it out as best I can. I included the NavigationStack as I found that in similar responses to other Picker posts. Others said it worked buy did not for me.

As for the multiple HStacks is a formatting thing I am using on the form.

Other than the pickers everything works perfectly for me.

My issue is getting the selection from the Date Picker and other pickers loaded into my textfields for Date, Handle, Tee and others I want to create.

You said I have multiple brackets on one line. I don’t see that in my code at all so I am not sure what you mean.

I will repost with comments.

ok lets see if this abbreviated code helps.

  1. I removed the HStacks and as expected it altered the form view for the user from what we wanted so I will retain the HStacks as I do know how they work and impact the look.

  2. my form has about 20 fields. When i don’t use Pickers I am able to add, list and update all the fields for multiple records added.

  3. when I add the pickers, I am able to make selections but I can figure out how to get that selection to load into the field.

  4. The date picker selection should end up in $roundsdata.roundsDate

  5. the Handle picker is built from data created in another view and the pick list loads properly and I can select form it. However as in date how do i get the selection into $roundsdata.roundsHandle

I can’t find any examples of pickers anywhere that show how to save the selected value into a field stored in SwiftData. If you have an example like that it would be great.

This is my first attempt at creating an app so apologies for incorrect terms and sloppy code.

At the moment I have several views working as long as no pickers are involved.

import SwiftUI import SwiftData

struct RoundsEditView: View { @Bindable var roundsdata: RoundsData @Environment(.modelContext) private var modelContext

@State private var playDate = Date.now

@State private var selection: selectedTee = .White

@Query(sort: \PlayerData.playerHandle) private var players: [PlayerData]
@State private var selectedHandle: PlayerData? = nil

var body: some View {

        Form {
           HStack {
               Text("Course:")
               TextField("Course Name", text: $roundsdata.roundscourseName)
                    .textContentType(.name)
           }
            
            DatePicker("Date:", selection: $playDate,
                           displayedComponents: [.date])
            
            Picker("Handle:", selection: $selectedHandle) {
                Text("Select a Handle").tag(nil as PlayerData?)
                ForEach(players, id: \.self) {
                    player in Text(player.playerHandle)
                        .frame(maxWidth: .infinity, alignment: .leading)
                        .tag(player as PlayerData?)
                }
            }

I don't want to labour the point, but once you make a post that has code in it you need to look at that post and see whether you've put the backticks in the right place:

Anyway, have you tried adding an .onChange(of:) {} to the DatePicker to print out the value of the variable?

If it's being set correctly, you can then just manually set your value, i.e.:

DatePicker("Date:", selection: $playDate, displayedComponents: [.date])
.onChange(of: playDate) {
    roundsdata.roundsDate = playDate
}

The same applies for your Picker, but make sure you add the .onChange(of:) {} to the closing brace for the Picker and not on anything inside it, like the Text and ForEach items.

Thank you. I was able to get the DatePicker work. I do get an error on the other picker using data from another view to populate the sort.

The data model field roundsHandle is defined as text.

here is the code and error

@Query(sort: \PlayerData.playerHandle) private var players: [PlayerData]
@State private var selectedHandle: PlayerData? = nil

var body: some View {

        Form {

            
            Picker("Handle:", selection: $selectedHandle) {
                Text("Select a Handle").tag(nil as PlayerData?)
                ForEach(players, id: \.self) {
                    player in Text(player.playerHandle)
                        .tag(player as PlayerData?)
                }
            }
            .onChange(of: selectedHandle) {
                roundsdata.roundsHandle = selectedHandle
            }

The error message is on the .onchange Cannot assign value of type 'PlayerData?' to type 'String'

so i thought it because I set PlayerData? to nil, I changed that to “ “ and get an error doing that.

Your first item in the Picker is Text("Select a Handle") and you've set the tag to nil. So, if someone picks the first item then the selectedHandle is going to be nil. That cannot be stored in roundsdata.roundsHandle, because you've said it's 'text' (I'm sure you meant String).

So, just don't update roundsdata.roundsHandle in onChange when it's nil, i.e.:

.onChange(of: selectedHandle) {
    if(selectedHandle != nil) {
        roundsdata.roundsHandle = selectedHandle
    }
} 

Next, your players in the ForEach have a player value that you're setting the tag to, so when someone picks something other than the first item (which is nil) it will attempt to set roundsdata.roundsHandle to that value, but your tag is player as PlayerData?.

That means you're trying to set roundsdata.roundsHandle to an Optional(PlayerData). That's why you're getting the error.

You need to set the tag to a String value from the player, not to a PlayerData object.

You have Text(player.playerHandle) so the player.playerHandle is a String. I think that's what you need to set the tag to, i.e.:

Picker("Handle:", selection: $selectedHandle) {
    Text("Select a Handle").tag(nil)

    ForEach(players, id: \.self) { player in
        Text(player.playerHandle)
            .tag(player.playerHandle)
    }
}
.onChange(of: selectedHandle) {
    if(selectedHandle != nil) {
        roundsdata.roundsHandle = selectedHandle
    }
} 

It looks like you don't completely understand how these pickers work because you're over-complicating it. This might help:

Picker("Select something", selection: $thisIsPopulatedWithTheThingSelected) {
    // List the things we want in the picker, like days of the week
    ForEach(myArrayOfDayStrings, id: \.self) { day in
        Text(day) // Shows Monday-Sunday
            .tag(day) // For Monday, the tag is Monday. For Tuesday, it's Tuesday etc.

// When someone picks Monday, $thisIsPopulatedWithTheThingSelected becomes Monday. Pick Tuesday and it's Tuesday.
    }
}
.onChange(of: thisIsPopulatedWithTheThingSelected) {
    print("You picked \(thisIsPopulatedWithTheThingSelected)")
}

Thank you, much appreciated.

However, that code gives me two errors.

Generic parameter 'V' could not be inferred

Cannot assign value of type 'PlayerData?' to type 'String'

Part of my issue is I have found so many variations of Pickers people have built that I have altered the pickers too many times trying to resolve. I was using hackingwithswiftui quite a bit but much has changed since those postings. I see that .onChange has been deprecated come iOS 17 so i expect much of what I am trying to do now may break in the future.

But rather than take more of your time I will review the last info your shared for me to review and see if I can figure this out.

Picker("Handle:", selection: $selectedHandle) {
    Text("Select a Handle").tag(nil)
//Generic parameter 'V' could not be inferred

ForEach(players, id: \.self) { player in
    Text(player.playerHandle)
        .tag(player.playerHandle)
  }
}
onChange(of: selectedHandle) {
     if(selectedHandle != nil) {
        roundsdata.roundsHandle = selectedHandle
// Cannot assign value of type 'PlayerData?' to type 'String'
     }  
} 

.onChange has not been deprecated. It has changed. I've given you the current non-deprecated version.

Accepted Answer

Apple developer indicates it had been deprecated For iOS versions 17.0

https://developer.apple.com/documentation/swiftui/view/onchange(of:perform:)

in any case I still get errors with the picker code. I will search for the answer.

thank you for your input.

For other reviewers with a similar issue. I resolved it partially from here and finally from Stackoverflow forum to a few small changes.

here is the code that works for me I changed prior response as follows:

changed:
@State private var selectedHandle: PlayerData? = nil
to
@State private var selectedHandle: String? = "Select Handle"


HStack {
     Text("Handle:")
     Text(roundsdata.roundsHandle)
      Picker("", selection: $selectedHandle) {
          Text("Select a Handle").tag(" ")
     //  changed tag(nil) to tag(“ “)
                 
         ForEach(players, id: \.self) { player in
              Text(player.playerHandle)
               .tag(player.playerHandle)
         }
       }
          onChange(of: selectedHandle) {
              if(selectedHandle != “ ") {
                 roundsdata.roundsHandle = selectedHandle!
      // changed != nil to != “ “   both work but given all is String I went with != “ “  if someone can say why to use != nil let me know
      // changed selectedHandle to selectedHandle!
           }
    }
}
NavigationStack Fatal error: ‘try!
 
 
Q