简体   繁体   English

无法从核心数据加载 SwiftUI 选择器选择并显示为选择

[英]Can't Load SwiftUI Picker Choice from Core Data and Display as Selection

I have a SwiftUI app that persists data in CoreData .我有一个SwiftUI应用程序,可以将数据保存在CoreData I want to have a Picker where the user can choose an item (from one entity) and then store that information in another entity to be displayed as the Picker selection.我想要一个选择器,用户可以在其中选择一个项目(从一个实体中),然后将该信息存储在另一个实体中以显示为选择器选择。

I have an Entity named Patient where data is added by the user.我有一个名为 Patient 的实体,其中数据由用户添加。 I have an Entity named Clinic that is a list of objects created by the user.我有一个名为 Clinic 的实体,它是用户创建的对象列表。 The purpose is to use the picker to rapidly add information without repeatedly typing the items for each Patient record.目的是使用选取器快速添加信息,而无需为每个患者记录重复键入项目。

In Swift , I did this by attaching a UIPicker to a TextField.Swift ,我通过将 UIPicker 附加到 TextField 来做到这一点。 That worked fine.那工作得很好。 I have not been able to do the equivalent in SwiftUI.我无法在 SwiftUI 中做同样的事情。 I can make the creation and population of the picker data and I successfully save changes to the Patient entity, but I have not been able to load the Patient Clinic data into the picker as the default when the Detail View is loaded.我可以创建和填充选择器数据,并成功保存对患者实体的更改,但我无法在加载详细信息视图时将患者诊所数据加载到选择器中作为默认值。

This piece of the app is equivalent to the master/detail style.应用程序的这部分相当于主/细节样式。 The DetailView is:细节视图是:

struct DetailView: View {

    @Environment(\.managedObjectContext) var managedObjectContext
    @Environment(\.presentationMode) var presentationMode
    @FetchRequest(fetchRequest: Clinic.getAllClinics()) var clinics: FetchedResults<Clinic>
    @State private var selectClinicItem: Int = 0
    var patient: Patient

    @State private var updatedFirstName: String = "No First Name"
    @State private var updatedLastName: String = "No Last Name"
    @State private var updatedClinic: String = "Clinic Not Chosen"
    @State private var chosenClinicUUID: UUID = UUID()

    var body: some View {

        ScrollView {
            Group {//top group
                VStack {
                    MyDataCell(tfData: $updatedFirstName, passedInLabel: "First Name", patient: patient, patientAttribute: patient.firstName ?? "No First")
                }//Top VStack - 8 views
            }//top Group

            Group {//second group
                Form {
                    Picker(selection: self.$chosenClinicUUID, label: Text("Choose Clinic")) {
                        ForEach(clinics) { c in
                            Text("\(c.name ?? "no name")")
                        }
                    }
                    .frame(width:320, height: 30)
                }//Form
                .frame(width:350, height: 200)
                .clipShape(RoundedRectangle(cornerRadius: 12))
                .overlay(RoundedRectangle(cornerRadius: 12)
                .stroke(Color.gray, lineWidth: 2))
                .padding(.leading, 12)
                .padding(.top, 20)
                .padding(.bottom, 20)
            }//second Group

        }//scroll or top level Form

            .modifier(AdaptsToSoftwareKeyboard())
            .navigationBarTitle("View and Edit", displayMode: .inline)
            .navigationBarItems(trailing: Button(action: {

                self.patient.firstName = self.updatedFirstName
                self.patient.lastName = self.updatedLastName
                self.patient.clinicName = self.updatedClinic
                self.patient.clinicID = self.chosenClinicUUID

                let n = self.clinics.filter { $0.id == self.patient.clinicID }

                if n.count > 0 {
                    self.patient.clinicName = n[0].name
                }

                do {
                    try self.managedObjectContext.save()
                } catch {
                    print(error)
                }

                self.updatedFirstName = ""
                self.updatedLastName = ""
                self.updatedClinic = ""

                self.presentationMode.wrappedValue.dismiss()

            }) {
                Text("Save")
            })

    }//body
}

And for reference, the Patient class:作为参考,患者类:

public class Patient : NSManagedObject, Identifiable {
    @NSManaged public var id: UUID
    @NSManaged public var firstName: String?
    @NSManaged public var lastName: String?
    @NSManaged public var clinicName: String?
    @NSManaged public var clinicID: UUID
}

extension Patient {
    static func getAllPatients() -> NSFetchRequest<Patient> {
        let request: NSFetchRequest<Patient> = Patient.fetchRequest() as! NSFetchRequest<Patient>
        let sortDescriptor = NSSortDescriptor(key: "lastName", ascending: true)
        request.sortDescriptors = [sortDescriptor]
        return request
    }
}

The Clinic class:诊所类:

public class Clinic : NSManagedObject, Identifiable {
    @NSManaged public var id: UUID
    @NSManaged public var name: String?
    @NSManaged public var comment: String?
    @NSManaged public var isShown: Bool
}

extension Clinic {
    static func getAllClinics() -> NSFetchRequest<Clinic> {
        let request: NSFetchRequest<Clinic> = Clinic.fetchRequest() as! NSFetchRequest<Clinic>
        let sortDescriptor = NSSortDescriptor(key: "name", ascending: true)
        request.sortDescriptors = [sortDescriptor]
        return request
    }
}

在此处输入图片说明 在此处输入图片说明

Any guidance would be appreciated.任何指导将不胜感激。 Xcode Version 11.2.1 (11B500) Xcode 版本 11.2.1 (11B500)

This is what I did, a dummy instance of Icon这就是我所做的,一个 Icon 的虚拟实例

  @FetchRequest(
    entity: Icon.entity(),
    sortDescriptors: []
  ) var coreDataIcon: FetchedResults<Icon>

  @State private var oneCoreDataIconIndex: Int = 0

  var body: some View {

    Form {

        Picker("Select Icon", selection: $oneCoreDataIconIndex) {
          ForEach (0..<coreDataIcon.count) {
            Image(systemName: self.coreDataIcon[$0].wrappedIcon)
              .tag($0)
              .font(.title)
          }//ForEach

        }//Picker

      }//Form

... later in my code, I was able to add the relationship ...稍后在我的代码中,我能够添加关系

oneAccount.icon = self.coreDataIcon[self.oneCoreDataIconIndex]

in your case, you can do在你的情况下,你可以做

    @State private var chosenClinicIndex: Int = 0

...and ...和

       Picker(selection: $chosenClinicIndex, label: Text("Choose Clinic")) {
          ForEach(0..<clinics.count) {
            Text("\(self.clinics[$0].name ?? "no name")").tag($0)
          }
        }

later in your code稍后在您的代码中

self.patient.clinicID = self.clinics[self.chosenClinicIndex].id

this will also show an initial clinic before you pick这也会在您选择之前显示一个初始诊所

like mine像我的在此处输入图片说明

Try using a Int (in combination with an array) and not the actual UUID as the selection variable.尝试使用Int (结合数组)而不是实际的UUID作为选择变量。 Check out this .看看这个

Solved the problem by manually setting the selected index during Init.通过在Init期间手动设置所选索引解决了问题。 Seems like a strange way to do it.似乎是一种奇怪的方法。

struct MyView: View {
    ...
    @ObservedObject var model = VideoDetailsModel()
    @State var selectedCategoryIndex : Int = -1

    // Init with initial model
    init(onDismiss: @escaping (VideoDetails?) -> ()) {
        self.onDismiss = onDismiss
    }

    // Init with existing model
    init(model: VideoDetailsViewModel, onDismiss: @escaping (VideoDetails?) -> ()) {
        self.model = model
    
        self.onDismiss = onDismiss
        let selectedIndex = self.model.categories.categories.firstIndex(where: {
            return $0 == self.model.videoModel?.categories[0]
        }) ?? -1
        
        // Force the set state here since initialisation is optional
        _selectedCategoryIndex = .init(initialValue: selectedIndex)
    }
    
    var body: some View {
    ... 
            Picker(selection: $selectedCategoryIndex , label: Text("Category")) {
                ForEach(0..<self.model.categories.categories.count, id: \.self) { index in
                    Text(self.model.categories.categories[index])
                }
            }
    ... 
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM