UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: BucketList unable to load saved data

Forums > 100 Days of SwiftUI

I am getting an error of "unable to load saved data" (Xcode 12.3 - Simulator iPhone Xs 14.3) - log shows the following

file:///Users/xxx/Library/Developer/CoreSimulator/Devices/E4CA751B-F8E4-4879-A8A5-247B106C5480/data/Containers/Data/Application/D0EEBC33-1FB9-4A54-BE87-0AE410C44337/Documents/SavedPlaces
Unable to load saved data.
file:///Users/xxx/Library/Developer/CoreSimulator/Devices/E4CA751B-F8E4-4879-A8A5-247B106C5480/data/Containers/Data/Application/D0EEBC33-1FB9-4A54-BE87-0AE410C44337/Documents/SavedPlaces
Unable to load saved data.
Unlocked
2021-01-27 21:13:51.289156+1100 BucketList[1781:64283] Metal API Validation Enabled

ContentView code is.

import LocalAuthentication
import MapKit
import SwiftUI

struct ContentView: View {

    @State private var centerCoordinate = CLLocationCoordinate2D()
    @State private var locations = [CodableMKPointAnnotation()]

    @State private var selectedPlace: MKPointAnnotation?
    @State private var showingPlaceDetails = false
    @State private var showingEditScreen = false

    @State private var isUnlocked = false

    var body: some View {
        ZStack {
            if isUnlocked {
                MapView(centerCoordinate: $centerCoordinate, selectedPlace: $selectedPlace, showingPlaceDetails: $showingPlaceDetails, annotations: locations)
                    .edgesIgnoringSafeArea(.all)
                Circle()
                    .fill(Color.blue)
                    .opacity(0.3)
                    .frame(width: 32, height: 32)
                VStack {
                    Spacer()
                    HStack {
                        Spacer()
                        Button(action: {
                            let newLocation = CodableMKPointAnnotation()
                            newLocation.coordinate = self.centerCoordinate
                            newLocation.title = "Example Location"
                            self.locations.append(newLocation)
                            self.selectedPlace = newLocation
                            self.showingEditScreen = true
                        }) {
                            Image(systemName: "plus")
                        }
                        .padding()
                        .background(Color.black.opacity(0.75))
                        .foregroundColor(.white)
                        .font(.title)
                        .clipShape(Circle())
                        .padding(.trailing)
                    }
                }
            } else {
                Button("Unlock places") {
                    self.authenticate()
                }
                .padding()
                .background(Color.blue)
                .foregroundColor(.white)
                .clipShape(Capsule())
            }
        }
        .alert(isPresented: $showingPlaceDetails) {
            Alert(title: Text(selectedPlace?.title ?? "Unknown"), message: Text(selectedPlace?.subtitle ?? "Missing place information"), primaryButton: .default(Text("OK")), secondaryButton: .default(Text("Edit")) {
                self.showingEditScreen = true
            })
        }
        .sheet(isPresented: $showingEditScreen, onDismiss: saveData) {
            if self.selectedPlace != nil {
                EditView(placemark: self.selectedPlace!)
            }
        }
        .onAppear(perform: loadData)
    }

    func getDocumentsDirectory() -> URL {
        let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        return paths[0]
    }

    func loadData() {
        let filename = getDocumentsDirectory().appendingPathComponent("SavedPlaces")
        print(filename)
        do {
            let data = try Data(contentsOf: filename)
            locations = try JSONDecoder().decode([CodableMKPointAnnotation].self, from: data)
        } catch {
            print("Unable to load saved data.")
        }
    }

    func saveData() {
        do {
            let filename = getDocumentsDirectory().appendingPathComponent("SavedPlaces")
            print(filename)
            let data = try JSONEncoder().encode(self.locations)
            try data.write(to: filename, options: [.atomicWrite, .completeFileProtection])
            print("Data saved")
        } catch {
            print("Unable to save data.")
        }
    }

    func authenticate() {
        let context = LAContext()
        var error: NSError?

        if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
            let reason = "Please authenticate yourself to unlock your places."

            context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { success, autentificationError in

                DispatchQueue.main.async {
                    if success {
                        self.isUnlocked = true
                        print("Unlocked")
                    }
                    else {
                        //error
                    }
                }
            }
        } else {
            //no biometrics
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Any clues. Regards

3      

Hi Quin, I wish I could help, I too am stuck on the same project with a problem that won't allow me to save my pins to IOS storage. Anyway, one thing I picked up on reading your code (although I'm sure it won't be much help) is that Paul had his 'locations' property with the initialiser brackets outside the array: so [CodableMKPointAnnotation]()

3      

Hi Quin, I too had the same problem. In my case it didn't work because decoding of title and subtitle in the CodablePointAnnotation class caused an error (which you don't see cause it's caught in the ContentView) I changed the "title = try container.decode(String.self, forKey: title)" in "title = try? container.decode(String.self, forKey: title) and did the same for subtitle. That worked for me. But I'm not sure if this is the proper solution. Still learning...

3      

Hello Roger. Thank you for that. I don't realy understand why that should work work but it seems to do the trick. All I noticed in your text was a missing "." before "title"

title = try? container.decode(String.self, forKey: .title)

Like you still learning :-)

3      

BUILD THE ULTIMATE PORTFOLIO APP Most Swift tutorials help you solve one specific problem, but in my Ultimate Portfolio App series I show you how to get all the best practices into a single app: architecture, testing, performance, accessibility, localization, project organization, and so much more, all while building a SwiftUI app that works on iOS, macOS and watchOS.

Get it on Hacking with Swift+

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.