1

I was very kindly helped to allow my picker to select a value from my Firestore database. What I would like to do is once that value is selected in my picker I would like to be able to show that value in other views. I have tried setting this up using UserDefaults but I'm not sure that's the way to go? If you could suggest a better method I'd be more than grateful. My code currently is below.

The value in the below code returns Unknown School each time but without the user defaults works flawlessly in fetching the data.

Thanks in advance.

import SwiftUI
import Firebase

struct SchoolDetailsView: View {
    @ObservedObject var schoolData = getSchoolData()
    @State private var selectedSchool = UserDefaults.standard.string(forKey: "") // `schoolName.id` is of type String

    var body: some View {
        VStack {
                Form {
                    Section {
                        Picker(selection: $selectedSchool, label: Text("School Name")) {
                            ForEach(schoolData.datas, id: \.id) {
                                Text($0.name)
                            }
                        }
                        Text("Selected School: \(selectedSchool ?? "Unknown School")")
                    }
                }.navigationBarTitle("School Selection")
            }
        }

struct SchoolPicker_Previews: PreviewProvider {
    static var previews: some View {
        SchoolDetailsView()
    }
}

class getSchoolData : ObservableObject{
    
    @Published var datas = [schoolName]()
    
    init() {
        
        let db = Firestore.firestore()
        
        db.collection("School Name").addSnapshotListener { (snap, err) in
            
            if err != nil{
                
                print((err?.localizedDescription)!)
                return
            }
            
            for i in snap!.documentChanges{
                
                let id = i.document.documentID
                let name = i.document.get("Name") as! String
                
                self.datas.append(schoolName(id: id, name: name))
            }
        }
    }
}

struct schoolName : Identifiable {
    
    var id : String
    var name : String
}
}
LMA
  • 71
  • 1
  • 7

1 Answers1

3

First, the UserDefaults key for your variable can't be empty:

@State private var selectedSchool: String = UserDefaults.standard.string(forKey: "selectedSchool") ?? "Unknown School"

Then you can use onReceive to update the variable:

.onReceive(Just(selectedSchool)) {
    UserDefaults.standard.set($0, forKey: "selectedSchool")
}

Full code:

import Combine
import Firebase
import SwiftUI

struct SchoolDetailsView: View {
    @ObservedObject var schoolData = getSchoolData()
    @State private var selectedSchool = UserDefaults.standard.string(forKey: "selectedSchool")

    var body: some View {
        VStack {
            Form {
                Section {
                    Picker(selection: $selectedSchool, label: Text("School Name")) {
                        ForEach(schoolData.datas, id: \.id) {
                            Text($0.name)
                        }
                    }
                    .onReceive(Just(selectedSchool)) {
                        UserDefaults.standard.set($0, forKey: "selectedSchool")
                    }
                    Text("Selected School: \(selectedSchool)")
                }
            }.navigationBarTitle("School Selection")
        }
    }
}

Note that in SwiftUI 2 / iOS 14 you can use @AppStorage instead.

pawello2222
  • 46,897
  • 22
  • 145
  • 209
  • Hi Pawello, as always thank you for the update. I have tried that glad I was along the right lines. I had tried to have it without an empty key but it didn't seem to work but now I get why so thanks. Although that code compiles correctly. It no longer seems to let me select the school. The selected school will not change from the nil "Unknown School" – LMA Oct 30 '20 at 08:45
  • 1
    @LMA Yes, the `selectedSchool` must be also of type `String` (as is the `schoolName.id`). I updated my answer. – pawello2222 Oct 30 '20 at 09:29