Как работать с основными / подробными данными CoreData между представлениями SwiftUI - PullRequest
0 голосов
/ 15 февраля 2020

Я имею дело с тем, как передать параметр, выбранный в главном представлении, в предикат CoreData в подробном представлении. У меня есть это главное представление

struct ContentView: View {

@State private var selectedCountry: Country?
@State private var showSetting = false

@FetchRequest(entity: Country.entity(),
              sortDescriptors: [NSSortDescriptor(keyPath: \Country.cntryName, ascending: true)]
) var countries: FetchedResults<Country>

var body: some View {
    NavigationView {
        VStack {
            Form {
                Picker("Pick a country", selection: $selectedCountry) {
                    ForEach(countries, id: \.self) { country in
                        Text(country.cntryName ?? "Error").tag(country as Country?)
                    }
                }
                if selectedCountry != nil {
                    Years(cntryName: selectedCountry?.cntryName! ?? "")
                }
            }
        }
        .navigationBarTitle("UNECE Data")
        .navigationBarItems(trailing: Button("Settings", action: {
            self.showSetting.toggle()
        }))
    }
    .sheet(isPresented: $showSetting) {
        SettingsView(showSetting: self.$showSetting)
    }
}
}

, где я использую средство выбора, чтобы выбрать название страны (из сущности CoreData Country и ее атрибута cntryName) и передать его в качестве строкового значения в представление Years, которое закодировано следующим образом

struct Years: View {

var cntryName: String
@State private var selectedDataRow: Data?
@State private var result: NSFetchRequestResult

@FetchRequest(entity: Data.entity(),
              sortDescriptors: [NSSortDescriptor(keyPath: \Data.dataYear, ascending: true)],
              predicate: NSPredicate(format: "dataCountry == %@", "UK"), animation: .default
) var data: FetchedResults<Data>

var body: some View {
    Picker("Year", selection: $selectedDataRow) {
        ForEach(data, id: \.self) { dataRow in
            Text(dataRow.dataYear ?? "N/A")
        }
    }
    .pickerStyle(WheelPickerStyle())
    .frame(width: CGFloat(UIScreen.main.bounds.width), height: CGFloat(100))
    .clipped()
    .onAppear() {
        let request = NSFetchRequest<Data>(entityName: "Data")
        request.sortDescriptors = [NSSortDescriptor(key: "dataYear", ascending: true)]
        request.predicate = NSPredicate(format: "dataCountry == %@", self.cntryName)
        do {
            self.result = try context.fetch(request) as! NSFetchRequestResult
            print(self.result)
        } catch let error {
            print(error)
        }
    }
}
}

Он отлично работает с @FetchRequest и FetchedResults, хранящимися в данных var, но мне интересно, как построить здесь предикат на основе переданного названия страны. Чтобы преодолеть это, я решил использовать раздел onAppear и classi c NSFetchRequest и NSFetchRequestResult, что вызывает ошибку компилятора "Years.Type" не преобразуется в "(String, NSFetchRequestResult, FetchRequest) -> Years" "в строке

Years(cntryName: selectedCountry?.cntryName! ?? "")

структуры ContentView. Ошибка исчезнет, ​​если я прокомментирую строку

@State private var result: NSFetchRequestResult

в структуре Years, но это, очевидно, вызывает другую ошибку. Итак, я потерян в кругу. Какая рекомендуемая практика здесь, пожалуйста? Спасибо.

1 Ответ

0 голосов
/ 16 февраля 2020

Наконец-то я нашел способ благодаря этому сообщению SwiftUI использует предикат отношений с параметром struct в FetchRequest

struct Years: View {

var request: FetchRequest<Data>
var result: FetchedResults<Data> {
    request.wrappedValue
}

@State private var selectedDataRow: Data?

init(cntryName: String) {
    self.request = FetchRequest(entity: Data.entity(),
                           sortDescriptors: [NSSortDescriptor(keyPath: \Data.dataYear, ascending: true)],
                           predicate: NSPredicate(format: "dataCountry == %@", cntryName), animation: .default)
}

var body: some View {
    VStack {
        Picker("Year", selection: $selectedDataRow) {
            ForEach(result, id: \.self) { dataRow in
                Text(dataRow.dataYear ?? "N/A").tag(dataRow as Data?)
            }
        }
        .pickerStyle(WheelPickerStyle())
        .frame(width: CGFloat(UIScreen.main.bounds.width), height: CGFloat(100))
        .clipped()
        VStack(alignment: .leading, spacing: 10) {
        HStack {
            Text("Total polutation: ")
                .alignmentGuide(.leading) { dimension in
                    10
            }
            if selectedDataRow != nil {
                Text(String(describing: selectedDataRow!.dataTotalPopulation))
            } else {
                Text("N/A")
            }
        }
        }}
}
}
...