Search code examples
core-dataswiftui

SwiftUI Core Data Object Return from Picker


I have two Core Data Entities (in CloudKit) which have a relationship between them. In the updating of one entity, I am trying to add the related entity by adding the result from a user selection, via a picker.

The issue I am facing is that I can't get the picker to return the record as the selection - it's always null. I have developed the following test code to highlight the specific case. The picker populates and I can make it return anything other than the actual record - but to insert in the relationship, I need the record itself. Here is the picker test code. Selection is ALWAYS empty.

I would appreciate direction.

struct TestView: View {
    
    @Environment(\.managedObjectContext) var viewContext

    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \Player.familyName, ascending: true)],
        animation: .default)
    private var players: FetchedResults<Player>
    
    @State var selection: Player?
    
    var body: some View {
        VStack{
            Picker("", selection: $selection){
                ForEach(players, id: \.self){ (player: Player) in
                    Text(player.givenName!).tag(player.self)
                }
            }
            Text(((selection?.familyName ?? "default")))
            Text("\(players.count)")
        }
    }
}

The Player entity looks like this:

enter image description here


Solution

  • A helpful commenter on the Apple forums showed me the answer - which was to do with making sure the selection variable was not optional:

    import SwiftUI
    import CoreData
    struct ContentView: View {
        @FetchRequest private var players: FetchedResults<Player>
        @State private var selection: Player
        init(moc: NSManagedObjectContext) {
            let fetchRequest: NSFetchRequest<Player> = Player.fetchRequest()
            fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \Player.familyName, ascending: true)]
            fetchRequest.predicate = NSPredicate(value: true)
            self._players = FetchRequest(fetchRequest: fetchRequest)
            do {
                let firstPlayer = try moc.fetch(fetchRequest)
                self._selection = State(initialValue: firstPlayer[0])
            } catch {
                fatalError("Uh, fetch problem...")
            }
        }
        var body: some View {
            VStack{
                Picker("", selection: $selection){
                    ForEach(players) { (player: Player) in
                        Text(player.givenName ?? "")
                            .tag(player)
                    }
                }
                Text(selection.familyName ?? "No family name")
                Text("\(players.count)")
            }
        }
    }