christophriepe
christophriepe

Reputation: 1703

Best Practice for using a FetchedResults for populating a SwiftUI Picker

I am currently working with CoreData FetchedResults and SwiftUIs PickerView. While doing so I encountered a problem when using the FetchedResults to populate a PickerView:

I obviously can use the FetchedResults to populate the PickerView but what solution is the best (also from UI / UX perspective) for defining the @State for the selected Result?

@FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \User.lastName, ascending: true)], animation: .default) private var users: FetchedResults<User>
@State var user: User = User()

// ...

Picker(selection: $user, label: Text("User")) {
    ForEach(users) { user in
        Text(lastName).tag(user)
    }
}

This does work, however it is probably not the most elegant way to create a new empty User Object to set it as the default.

Does anyone of you have a better Idea / Best Practice for solving this probably often problem?

Upvotes: 3

Views: 692

Answers (1)

davidev
davidev

Reputation: 8547

If you doesn't want to create a dummy User() all the time, which isn't good practice as you mentioned, you have to do your FetchRequest in your init() or pass your FetchedResult to another view.

Here is a solution with another view

struct ContentView : View {
    
    @FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \User.lastName, ascending: true)], animation: .default) private var users: FetchedResults<User>

    var body : some View {
        PickerView(users: Array(users))
    }
}

struct PickerView : View {

    var users : [User]
    @State var selectedUser : User?
    
    init(users: [User]) {
        self.users = users
        self._selectedUser = State(initialValue: users.first)
    }
    
    var body : some View {
        Picker(selection: $selectedUser, label: Text("Users")) {
            ForEach(users) { user in
                Text(user.lastName ?? "").tag(user as User?)
            }
        }

    }
}

Edit:

Actually you can just declare your Person as optional. So you do not have to provide a default. When fetching it will automatically move to the first Item in the picker. If you wish to select a differently you can use that method above. Regarding the FetchRequest in the init() it posted a answer a couple of month ago here

Upvotes: 3

Related Questions