0

I have this code in my SwiftUI project in works well

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: \Country.cntryName) { country in
                        Text(country.cntryName ?? "Error").tag(country as Country?)
                    }
                }
                if selectedCountry != nil {
                    DetailView(cntryName: (selectedCountry?.cntryName!)!)
                }
            }
        }
        .navigationBarTitle("UNECE Data")
        .navigationBarItems(trailing: Button("Settings", action: {
            self.showSetting.toggle()
        }))
    }
    .sheet(isPresented: $showSetting) {
        SettingsView(showSetting: self.$showSetting)
    }
}
}

However I need to call FetchRequest dynamically end reload Picker view when SettingsView dismiss. Possibly I should use @ObservableObject but how to put there fetch request and use result in the Picker view ForEach? Thanks for hints.

Dawy
  • 770
  • 6
  • 23

3 Answers3

1

You can customize most part of your FetchRequest:

@FetchRequest(entity: Country.entity(),
          sortDescriptors:  ObservableObject.sortDesc,
          predicate : ObservableObject.predicate
  ) var countries: FetchedResults<Country>
E.Coms
  • 11,065
  • 2
  • 23
  • 35
  • My issue is that when SettingsView is dismissed and Picker view reload countries FetchedResult it doubles items in the Picker because countries fetch data from Country entity. I need to clean countries somehow first. – Dawy Feb 22 '20 at 21:30
  • Is that your `id` problem? you may use `ForEach(countries, id: \Country.objectID)` – E.Coms Feb 22 '20 at 21:48
  • Doesn't seem to be the cause of problem. Result countries has 52 items when app is run. When SettingsView is shown and dismissed then countries is fetched again and has 104 items. This is what I need to fix. – Dawy Feb 22 '20 at 21:55
  • Did you add any countries in the settingsView? otherwise, where are the extra countries from? – E.Coms Feb 22 '20 at 22:55
0

I have reworked code like this

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

func getAllCountries() -> FetchRequest<Country> {
    let request = FetchRequest<Country>(entity: Country.entity(),
                  sortDescriptors: [NSSortDescriptor(keyPath: \Country.cntryName, ascending: true)])
    return request
}

but it reports fatal error "Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)" on ForEach line when runs.

Dawy
  • 770
  • 6
  • 23
0

In SettingsView I delete all data in Country entity, parse JSON file stored on my iCloud and save all data in Country entity.

Dawy
  • 770
  • 6
  • 23