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 theView Merchandise ...
button it will print the choice’s precise worth which isn’tnil
(the worth forNew 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?