0

I am creating an app that uses core data to save user data and whenever I save new data values it throws the error below. here is a screenshot of my .xcdatamodel A screenshot of my data structure here is my persistance.swift which came with the SwiftUI CoreData template


//
//  Persistence.swift
//  Permit Tracker
//
//  Created by Everett Wilber on 8/9/21.
//

import CoreData

struct PersistenceController {
    static let shared = PersistenceController()

    static var preview: PersistenceController = {
        let result = PersistenceController(inMemory: true)
        let viewContext = result.container.viewContext
//        for _ in 0..<10 {
//            let newItem = Item(context: viewContext)
//          newItem.coordinate = Date()
//        }
        do {
            try viewContext.save()
        } catch {
            // Replace this implementation with code to handle the error appropriately.
            // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            let nsError = error as NSError
            fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
        }
        return result
    }()

    let container: NSPersistentContainer

    init(inMemory: Bool = false) {
        container = NSPersistentContainer(name: "Permit_Tracker")
        if inMemory {
            container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
        }
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

                /*
                Typical reasons for an error here include:
                * The parent directory does not exist, cannot be created, or disallows writing.
                * The persistent store is not accessible, due to permissions or data protection when the device is locked.
                * The device is out of space.
                * The store could not be migrated to the current model version.
                Check the error message to determine what the actual problem was.
                */
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
    }
}

here is my ContentView.swift

//
//  ContentView.swift
//  Permit Tracker
//
//  Created by Everett Wilber on 8/9/21.
//

import SwiftUI
import CoreData
import CoreLocation
import BackgroundTasks

struct ContentView: View {
    @StateObject var locationViewModel = LocationViewModel()
    @Environment(\.managedObjectContext) private var viewContext
    
    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \Item.date, ascending: true)],
        animation: .default
    )
    private var items: FetchedResults<Item>

    @State var Recording = false
    @State var AllDrives: [DriveDetails] = []
    
    let locationManager = CLLocationManager()
    
    var body: some View {
        Group {
            VStack {
                if (Recording) {
                    TrackingView(locationViewModel: locationViewModel)
                        .onAppear(perform: {
                            print("appeared recording")
                        })
                } else {
                    List {
                        ForEach(0..<items.count, content: {i in
                            Drive(locationViewModel: locationViewModel, driveDetail: items[i].location?.driveDetail)
                        })
                    }
                    .onAppear(perform: {
                        print("appeared list", items.first?.date as Any)
                    })
                }
                HStack {
                    ToolBar(Recording: $Recording, StartRecording: startRecording, StopRecording: stopRecording)
                }
            }
        }
        .onAppear(perform: {
            locationViewModel.requestPermission()
        })
    }
    private func startRecording() {
        if CLLocationManager.locationServicesEnabled() {
            locationViewModel.locationManager.activityType = .automotiveNavigation
            locationViewModel.locationManager.startUpdatingLocation()
        } else {
            print("location denied")
        }
    }
    
    private func stopRecording() {
        if CLLocationManager.locationServicesEnabled() {
            
            
            locationViewModel.locationManager.stopUpdatingLocation()
            let allLocations = locationViewModel.allLocations
            let newDrive = locationDelist(locations: allLocations, date: allLocations.first?.timestamp ?? Date())
            
            let newItem = Item(context: viewContext)
            newItem.location = newDrive
            newItem.date = (allLocations.first?.timestamp ?? Date())
            
            print(
                "hasChanges:", viewContext.hasChanges,
                "\ninsertedObjects:", viewContext.insertedObjects
            )
            viewContext.userInfo.setValue("data", forKey: "use")
            
            do {
                try viewContext.save()
            } catch {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
//              let nsError = error as NSError
                print("error", error)
//              fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
            }
            locationViewModel.allLocations = []
        } else {
            print("location denied")
        }
    }
//
//    private func deleteItems(offsets: IndexSet) {
//        withAnimation {
//            offsets.map { items[$0] }.forEach(viewContext.delete)
//
//            do {
//                try viewContext.save()
//            } catch {
//                // Replace this implementation with code to handle the error appropriately.
//                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
//                let nsError = error as NSError
//                fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
//            }
//        }
//    }
    
}

private let itemFormatter: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateStyle = .short
    formatter.timeStyle = .medium
    return formatter
}()

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
    }
}

here is a screen recording of it running, the error happens when i stop recording location on line 88 of ContentView.swift

YouTube video of a simulator, simulating the app

once the app is quit, the data is lost.

when i saw 'NSKeyedUnarchiveFromData' should not be used to for un-archiving and will be removed in a future release in the log i looked through my code for NSKeyedUnarchiveFromData. As it turns out, i am using NSSecureUnarchiveFromDataTransformer (keyword secure) the issue with NSKeyedUnarchiveFromData is it is insecure.

I use a transformable data type because it stores a list of locations. this combined creates a list of lists of CLLocations (stored split up). here is the DriveDetails.swift file, where i have the classes that store DriveDetails which needs to be saved and convert it into CoreData. All of this is in my git

//
//  DriveDetails.swift
//  Permit Tracker
//
//  Created by Everett Wilber on 8/9/21.
//

import Foundation
import CoreLocation

class DriveDetails {
    init(Locations: [CLLocation]) {
        self.Locations = Locations
    }
    init(Count: Int, coordinatesLon: [Double], coordinatesLat: [Double] , altitudes: [Double], horizontalAccuracies: [Double], verticalAccuracies: [Double], courses: [Double], courseAccuracies: [Double], speeds: [Double], speedAccuracies: [Double], timestamps: [Date]) {
        for i in 0..<Count {
            let location: CLLocation = CLLocation(
                coordinate: CLLocationCoordinate2D(latitude: coordinatesLat[i], longitude: coordinatesLon[i]),
                altitude: altitudes[i],
                horizontalAccuracy: horizontalAccuracies[i],
                verticalAccuracy: verticalAccuracies[i],
                course: courses[i],
                courseAccuracy: courseAccuracies[i],
                speed: speeds[i],
                speedAccuracy: speedAccuracies[i],
                timestamp: timestamps[i]
            )
            self.Locations.append(location)
        }
    }
    var Date: Date {
        get {
            return Locations.first?.timestamp ?? Foundation.Date()
        }
    }
    var Locations: [CLLocation] = []
    var Locations2d: [CLLocationCoordinate2D] {
        get {
            var locs: [CLLocationCoordinate2D] = []
            for i in Locations {
                locs.append(i.coordinate)
            }
            return locs
        }
    }
}

@objc
public class locationDelist: NSObject {
    var coordinatesLon: [Double] = []
    var coordinatesLat: [Double] = []
    var altitudes: [Double] = []
    var horizontalAccuracies: [Double] = []
    var verticalAccuracies: [Double] = []
    var courses: [Double] = []
    var courseAccuracies: [Double] = []
    var speeds: [Double] = []
    var speedAccuracies: [Double] = []
    var timestamps: [Date] = []
    var date: Date
    
    init(locations: [CLLocation], date: Date) {
        self.date = date
        for location in locations {
            
            self.coordinatesLat.append(location.coordinate.latitude)
            self.coordinatesLon.append(location.coordinate.longitude)
            self.altitudes.append(location.altitude)
            
            self.horizontalAccuracies.append(location.horizontalAccuracy)
            self.verticalAccuracies.append(location.verticalAccuracy)
            
            self.courses.append(location.course)
            self.courseAccuracies.append(location.courseAccuracy)
            
            self.speeds.append(location.speed)
            self.speedAccuracies.append(location.speedAccuracy)
            
            self.timestamps.append(location.timestamp)
            
        }
    }
    var driveDetail: DriveDetails {
        get {
            DriveDetails(
                Count: timestamps.count,
                coordinatesLon: self.coordinatesLon,
                coordinatesLat: self.coordinatesLat,
                altitudes: self.altitudes,
                horizontalAccuracies: self.horizontalAccuracies,
                verticalAccuracies: self.verticalAccuracies,
                courses: self.courses,
                courseAccuracies: self.courseAccuracies,
                speeds: self.speeds,
                speedAccuracies: self.speedAccuracies,
                timestamps: self.timestamps
            )
        }
    }
}

class LocationToDataTransformer: NSSecureUnarchiveFromDataTransformer {
    
    override class func allowsReverseTransformation() -> Bool {
        return true
    }
    
    override class func transformedValueClass() -> AnyClass {
        return locationDelist.self
    }
    
    override class var allowedTopLevelClasses: [AnyClass] {
        return [locationDelist.self]
    }

    override func transformedValue(_ value: Any?) -> Any? {
        guard let data = value as? Data else {
            fatalError("Wrong data type: value must be a Data object; received \(type(of: value))")
        }
        return super.transformedValue(data)
    }
}

extension NSValueTransformerName {
    static let locationToDataTransformer = NSValueTransformerName(rawValue: "LocationToDataTransformer")
}

here is the git in the broken commit if it helps

finally, here is the logs that is printed right before the error occurs:

2021-08-12 13:52:14.718185-0400 Permit Tracker[66730:1242980] [general] 'NSKeyedUnarchiveFromData' should not be used to for un-archiving and will be removed in a future release
2021-08-12 13:52:14.718692-0400 Permit Tracker[66730:1242980] -[Permit_Tracker.locationDelist encodeWithCoder:]: unrecognized selector sent to instance 0x6000031fb2a0
2021-08-12 13:52:14.719395-0400 Permit Tracker[66730:1242980] *** -[NSKeyedArchiver dealloc]: warning: NSKeyedArchiver deallocated without having had -finishEncoding called on it.
2021-08-12 13:52:14.719792-0400 Permit Tracker[66730:1242980] [error] error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x6000020d18c0> , <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
CoreData: error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x6000020d18c0> , <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
2021-08-12 13:52:14.720159-0400 Permit Tracker[66730:1242980] [error] error: -executeRequest: encountered exception = <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo = (null)
CoreData: error: -executeRequest: encountered exception = <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo = (null)
2021-08-12 13:52:14.732536-0400 Permit Tracker[66730:1242980] [general] 'NSKeyedUnarchiveFromData' should not be used to for un-archiving and will be removed in a future release
2021-08-12 13:52:14.732890-0400 Permit Tracker[66730:1242980] -[Permit_Tracker.locationDelist encodeWithCoder:]: unrecognized selector sent to instance 0x6000031fb2a0
2021-08-12 13:52:14.733299-0400 Permit Tracker[66730:1242980] *** -[NSKeyedArchiver dealloc]: warning: NSKeyedArchiver deallocated without having had -finishEncoding called on it.
2021-08-12 13:52:14.733533-0400 Permit Tracker[66730:1242980] [error] error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x6000020c6f40> , <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
CoreData: error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x6000020c6f40> , <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
2021-08-12 13:52:14.733824-0400 Permit Tracker[66730:1242980] [error] error: -executeRequest: encountered exception = <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo = (null)
CoreData: error: -executeRequest: encountered exception = <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo = (null)
2021-08-12 13:52:14.734242-0400 Permit Tracker[66730:1242980] [general] 'NSKeyedUnarchiveFromData' should not be used to for un-archiving and will be removed in a future release
2021-08-12 13:52:14.734546-0400 Permit Tracker[66730:1242980] -[Permit_Tracker.locationDelist encodeWithCoder:]: unrecognized selector sent to instance 0x6000031fb2a0
2021-08-12 13:52:14.734930-0400 Permit Tracker[66730:1242980] *** -[NSKeyedArchiver dealloc]: warning: NSKeyedArchiver deallocated without having had -finishEncoding called on it.
2021-08-12 13:52:14.735153-0400 Permit Tracker[66730:1242980] [error] error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x6000020d18c0> , <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
CoreData: error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x6000020d18c0> , <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
2021-08-12 13:52:14.735339-0400 Permit Tracker[66730:1242980] [error] error: -executeRequest: encountered exception = <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo = (null)
CoreData: error: -executeRequest: encountered exception = <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo = (null)
2021-08-12 13:52:14.746477-0400 Permit Tracker[66730:1242980] [general] 'NSKeyedUnarchiveFromData' should not be used to for un-archiving and will be removed in a future release
2021-08-12 13:52:14.746945-0400 Permit Tracker[66730:1242980] -[Permit_Tracker.locationDelist encodeWithCoder:]: unrecognized selector sent to instance 0x6000031fb2a0
2021-08-12 13:52:14.747505-0400 Permit Tracker[66730:1242980] *** -[NSKeyedArchiver dealloc]: warning: NSKeyedArchiver deallocated without having had -finishEncoding called on it.
2021-08-12 13:52:14.747902-0400 Permit Tracker[66730:1242980] [error] error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x6000020d18c0> , <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
CoreData: error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x6000020d18c0> , <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)

here is the error

Error Domain=NSCocoaErrorDomain Code=134060 "A Core Data error occurred."

I've tried messing around with the xcdatafile it has been an all day problem.

a1cd
  • 17,884
  • 4
  • 8
  • 28
  • Very much code here that isn’t relevant but I assume the issue is related to the transformation of location. – Joakim Danielson Aug 12 '21 at 18:37
  • @JoakimDanielson that's what I assumed, but I can't figure out what part I got wrong. The error is incredibly vague and apple does not have any documentation on the error. "a core data error occurred" wow, helpful – a1cd Aug 12 '21 at 18:45
  • Well neither can we since we don't know how the transformation is done. But do you really need to go through the trouble of using Transformable when you could easily store the location as two Double properties, longitude and latitude? – Joakim Danielson Aug 12 '21 at 20:37
  • I need it to be a transformable because I need a list of lists. not just a list of locations – a1cd Aug 12 '21 at 21:35
  • Does this answer your question? ['NSKeyedUnarchiveFromData' should not be used to for un-archiving and will be removed in a future release](https://stackoverflow.com/questions/62589985/nskeyedunarchivefromdata-should-not-be-used-to-for-un-archiving-and-will-be-re) – lorem ipsum Aug 12 '21 at 23:33
  • if you look through the code, I actually have not used that class, I saw that in the error log and already looked through my code. Sadly it was no help. i am using `NSSecureUnarchiveFromDataTransformer` and so it is not the problem because its secure. – a1cd Aug 13 '21 at 00:20
  • If you need a list then you should create a new entity with a one-to-many relationship between the current one and the new one – Joakim Danielson Aug 13 '21 at 05:57
  • @JoakimDanielson so i can create an entity and use it in another entity? how? – a1cd Aug 13 '21 at 14:37
  • 1
    Like I said create a new entity with the needed attributes and then create a relationship between them. If you are unsure how then read the documentation or find a tutorial – Joakim Danielson Aug 13 '21 at 14:45
  • 1
    @JoakimDanielson is correct. Instead of having your `locationDelist` class, that should be an entity on a relationship. A good rule of thumb with CoreData is to keep it simple if you can. Simply put the properties into the Entity as Attributes. Also, you stored them as Arrays inside the class, but it appears that they should be stored as an Array of the class. I would recommend a One to Many relationship between your entities. Also, your Item entity should have an ID property so it is Identifiable. – Yrb Aug 13 '21 at 15:21

0 Answers0