HomeiOS Developmentios - Why does the SwiftUI Picker not present the right chosen...

ios – Why does the SwiftUI Picker not present the right chosen worth if it is set utilizing .onAppear


Background

I need a view that may enable the consumer to create a brand new core knowledge merchandise. That merchandise could have a hyperlink to a different core knowledge merchandise which the consumer will choose from a picker which might be pre-populated with a default merchandise chosen when the view first hundreds (probably the most relevent one for that consumer).

## Downside

However after I change the pickers “choice” variable through the .onAppear (within the precise code it is a modified model on .onAppear that solely runs the code the primary time .onAppear reveals however that is ok for this query) it does not change the picker’s chosen worth.

If I then change it once more utilizing say a button that runs the identical choice code it DOES change the picker.

Additionally if I add one thing that references the picker’s choice var (which is a @State. See instance code) it really works completely!

How one can replicate the problem

To duplicate the problem create a brand new challenge in Xcode (14.3), choose App and tick Use Core Information.

Now substitute the entire of the ContentView with the next code:

import SwiftUI
import CoreData

struct ContentView: View {
    @Atmosphere(.managedObjectContext) non-public var viewContext
    
    @FetchRequest(
        sortDescriptors: []
    ) var objects: FetchedResults<Merchandise>
    
    @State non-public var selectedItem: Merchandise?
    
    var physique: some View {
        Kind {
            // ---------------------------------------------
            // Uncommenting the subsequent line fixes the pickers!
            //let _ = selectedItem
            // ---------------------------------------------
            Picker ("A part of Merchandise Session", choice: $selectedItem) {
                Textual content("New Merchandise").tag(nil as Merchandise?)
                ForEach(objects) { merchandise in
                    Textual content("(merchandise.timestamp!.description)").tag(merchandise as Merchandise?)
                }
            }
            Button {
                ContentView.addItems(withViewContext: viewContext)
            } label: {
                Textual content("Add Objects")
            }
            Button {
                selectedItem = ContentView.getItem(withViewContext: viewContext)
            } label: {
                Textual content("Choose Random Merchandise")
            }
            Button {
                if (selectedItem != nil) {
                    print("Merchandise: (String(describing: selectedItem!.timestamp))")
                } else {
                    print("Merchandise is nil!")
                }
            } label: {
                Textual content("View Merchandise (print to console)")
            }
        }
        .onAppear {
            selectedItem = ContentView.getItem(withViewContext: viewContext)
            if (selectedItem != nil) {
                print("Merchandise: (String(describing: selectedItem!.timestamp))")
            } else {
                print("Merchandise is nil!")
            }
        }
    }
    
    static func addItems(withViewContext viewContext: NSManagedObjectContext) {
        for _ in 0..<10 {
            let newItem = Merchandise(context: viewContext)
            newItem.timestamp = Date().addingTimeInterval(-Double(Int.random(in: 1..<5000)))
        }
        do {
            attempt viewContext.save()
        } catch {
            let nsError = error as NSError
            fatalError("Unresolved error (nsError), (nsError.userInfo)")
        }
    }
    
    static func getItem(withViewContext viewContext: NSManagedObjectContext) -> Merchandise? {
        let fetchRequest: NSFetchRequest<Merchandise> = Merchandise.fetchRequest()
        fetchRequest.sortDescriptors = []
        
        var objects: [Item] = []
        do {
            // Fetch
            objects = attempt viewContext.fetch(fetchRequest)
            
            // Choose a random(ish) merchandise
            if (objects.rely > 0) {
                let randomInt = Int.random(in: 0..<objects.rely)
                print("Setting Merchandise: '(objects[randomInt].timestamp!.description)'")
                // Return the random(ish) merchandise
                return objects[randomInt]
            }
        } catch {
            print("Unable to Fetch Merchandise, ((error))")
        }
        
        return nil
    }
}

Then:

  • Operating the challenge in an iPhone 14 Professional Max simulator
  • Click on the Add Objects button so as to add some examples to your DB
  • Re-run the app within the simulator from Xcode to re-start it and you may see the picker nonetheless has New Merchandise chosen however for those who click on the View Merchandise ... button it will print the choice’s precise worth which isn’t nil (the worth for New Merchandise)!
  • When you change the choice use Choose Random Merchandise (which simply picks one other random merchandise for the picker) it should accurately change the Picker accurately.

Additionally for those who:

  • Restart the app once more
  • Click on the View Merchandise button
  • Choose the identical merchandise from the picker that was printed within the console it will not change the picker.
  • IF nevertheless you alter the picker to every other merchandise it WILL change the picker!

Unusual hack that fixes it

To see the picker working like I anticipated it to un-comment the road let _ = selectedItem (line 17) and re-run the app… Now instantly the picker is right!

Query

What is going on on right here. Is it a bug in Swift or am I doing one thing incorrect?

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments