【问题标题】:Can't Load SwiftUI Picker Choice from Core Data and Display as Selection无法从核心数据加载 SwiftUI 选择器选择并显示为选择
【发布时间】:2020-04-02 03:12:04
【问题描述】:

我有一个SwiftUI 应用程序将数据保存在CoreData 中。我想要一个 Picker 在哪里 用户可以选择一个项目(从一个实体),然后将该信息存储在 另一个要显示为 Picker 选择的实体。

我有一个名为 Patient 的实体,用户在其中添加数据。我有一个实体 名为 Clinic 的用户创建的对象列表。目的是使用 选择器可以快速添加信息,而无需重复键入每个项目 病历。

Swift 中,我通过将 UIPicker 附加到 TextField 来做到这一点。那工作得很好。我有 无法在 SwiftUI 中做同样的事情。我可以创造和人口 选择器数据,我成功地将更改保存到患者实体,但我有 无法将 Patient Clinic 数据作为默认值加载到选取器中 详细视图已加载。

这块app相当于master/detail样式。 DetailView 是:

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
}

作为参考,Patient 类:

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
    }
}

诊所类:

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
    }
}

任何指导将不胜感激。 Xcode 版本 11.2.1 (11B500)

【问题讨论】:

    标签: ios xcode core-data swiftui


    【解决方案1】:

    这就是我所做的,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
    

    ...稍后在我的代码中,我能够添加关系

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

    在你的情况下,你可以这样做

        @State private var chosenClinicIndex: Int = 0
    

    ...和

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

    稍后在您的代码中

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

    这还将在您选择之前显示初始诊所

    喜欢我的

    【讨论】:

    • 这对我没有任何影响。为了清楚起见,一旦在选择器中选择了一个项目,名称就会按预期显示 - 它是详细视图的初始显示,其中没有显示名称。
    【解决方案2】:

    尝试使用Int(与数组组合)而不是实际的UUID 作为选择变量。查看this

    【讨论】:

    • 这确实是在重申问题。我需要根据唯一的诊所 UUID 查找数组的索引 - 它必须是动态的。索引可以根据诊所实体中的新记录随时更改。
    • 好的,我明白了。也许在ForEach 循环中设置id 可能会解决问题。 SwiftUI 中没有 id 的 ForEach 循环仅用于常量数据,如下所述:stackoverflow.com/a/58508378/6594394
    • 我的 Core Data ManagedObjects 符合 Identifiable。问题是没有获取列表来填充选择器,也没有将选择保存到 Core Data。问题是将已选择并保存的项目显示为选择器选择。如上图所示,用户选择了 Carbon Health 作为诊所,但随后激活 DetailView 并没有显示保存的选择。
    【解决方案3】:

    通过在初始化期间手动设置所选索引解决了该问题。这似乎是一种奇怪的方式。

    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])
                    }
                }
        ... 
    }
    

    【讨论】:

      猜你喜欢
      • 2021-02-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-18
      • 1970-01-01
      相关资源
      最近更新 更多