Reputation: 946
I'm dealing with issue how to pass parameter selected in master view to CoreData predicate in detail view. I have this master view
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)
}
}
}
where I use Picker to select country name (from CoreData entity Country and its attribute cntryName) and pass it as String value to Years view which is coded like this
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)
}
}
}
}
It works fine with @FetchRequest and FetchedResults stored in var data but I'm wondering how to build predicate here based on passed country name. To overcome this I considered to use onAppear section and classic NSFetchRequest and NSFetchRequestResult which causes compiler error "'Years.Type' is not convertible to '(String, NSFetchRequestResult, FetchRequest) -> Years'" in the line
Years(cntryName: selectedCountry?.cntryName! ?? "")
of ContentView struct. Error disappear if I comment the line
@State private var result: NSFetchRequestResult
in Years struct but it obviously causes another error. So I'm lost in circle. What`s recommended practice here, please? Thanks.
Upvotes: 2
Views: 334
Reputation: 946
Finally I found the way thanks to this post SwiftUI use relationship predicate with struct parameter in 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")
}
}
}}
}
}
Upvotes: 0