swiftcore-dataxcdatamodel

renaming .xcdatamodeld file


I am kind of new to Swift/Xcode and currently building my first app. I am using CoreData to persist some objects. I would like to rename my .xcdatamodeld file but after doing so my app crashes immediately after running it in simulator with the following error message:

CoreData: error: Failed to load model named SnapShot Swift/UnsafeRawBufferPointer.swift:1137: Fatal error: UnsafeRawBufferPointer with negative count

When reverting the changes everything works fine again. I guess I have to adjust some references in my project but I don't know which and my research on the internet did not bring me any further which is why I am asking here now. I am using Xcode 15.1 if that is somehow important. I cleaned and rebuilt the project and also tried to search for any occurrences of the old name in the project with Xcode's search funtion but got no matches. Thank you for your help :)


Solution

  • The same question have been asked earlier also, if you see this post -- Rename xcdatamodel file

    But I was doing this on a fresh project and I didn't found any crash. There are two observations

    1. The renaming is not actually changing the file that is saved in depth.
    2. There was no crash if we update the name on NSPersistentContainer(name: "New_updated_name") here. But it will create a new core data file and all your data that have been saved on earlier file will not migrate into the new one.

    What I have tried --

    In the attached sample project first set the .xcdatamodeld as FirstModel e.g and then save some names in it,

    Then rename the .xcdatamodeld and try to print the values, you will not get the data saved earlier.

    Then again update the .xcdatamodeld to it's original name then you will get the data.

    DatabaseManager.swift

    import CoreData
    
    public class DatabaseManager {
    
        public static let fetchLimit = 10
    
        /// This variable keep record of the number of insert, delete operations currently in in progress
        private var numberOfAlterOperationsInprogress: Int = 0
    
        public init() {
            print("DatabaseManager init called")
        }
    
        deinit {
            print("DatabaseManager deinit called")
        }
    
        // MARK: - Core Data stack
        private lazy var persistentContainer: NSPersistentContainer = {
            let momdName = "CoreDataTest"
            let bundle = Bundle(for: type(of: self))
            guard let modelURL = bundle.url(forResource: momdName, withExtension: "momd") else {
                print("Crash - Error loading model from bundle")
                fatalError("Error loading model from bundle")
            }
            guard let mom = NSManagedObjectModel(contentsOf: modelURL) else {
                print("Crash - Error initializing mom from: ", modelURL)
                fatalError("Error initializing mom from: \(modelURL)")
            }
            let container = NSPersistentContainer(name: momdName, managedObjectModel: mom)
            container.loadPersistentStores(completionHandler: { (storeDescription, error) in
                if let error = error as NSError? {
                    print("Crash - Unresolved error: ", error)
                    fatalError("Unresolved error \(error), \(error.userInfo)")
                }
            })
            return container
        }()
    
        public func save(name: String) {
            let context = self.persistentContainer.viewContext
            guard let entity = NSEntityDescription.entity(forEntityName: "Student", in: context) else {
                print("No entity found with name - ", "Student")
                return
            }
            self.numberOfAlterOperationsInprogress += 1
            let dataStore = NSManagedObject(entity: entity, insertInto: context)
            dataStore.setValue(name, forKey: "name")
            do{
                try context.save()
                self.numberOfAlterOperationsInprogress -= 1
            }catch{
                self.numberOfAlterOperationsInprogress -= 1
            }
        }
    
        /// This function is used to fetch the data store records.
        /// - Parameter completion: An array of data store records. If any error occured then it will return an empty array
        public func fetchData(limit: Int = 1000, completion: @escaping ([Student]) -> Void) {
            let context = self.persistentContainer.viewContext
            let fetchRequest: NSFetchRequest<Student> = Student.fetchRequest()
            do {
                let objects = try context.fetch(fetchRequest)
                completion(objects)
            } catch {
                print("Error while performing fetch -", error.localizedDescription)
                completion([])
            }
        }
    }
    

    Student+CoreData.swift

    import Foundation
    import CoreData
    
    @objc(Student)
    public class Student: NSManagedObject {
    
    }
    

    Student+CoreDataProperties.swift

    import Foundation
    import CoreData
    
    
    extension Student {
    
        @nonobjc public class func fetchRequest() -> NSFetchRequest<Student> {
            return NSFetchRequest<Student>(entityName: "Student")
        }
    
        @NSManaged public var name: String?
    
    }
    
    extension Student : Identifiable {
    
    }
    

    ViewController.swift

    import UIKit
    
    class ViewController: UIViewController {
    
        @IBOutlet weak var nameTextField: UITextField?
    
        @IBOutlet weak var nameLabel: UILabel?
    
    
        let databaseManager = DatabaseManager()
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
        }
    
        @IBAction func saveAction(button: UIButton) {
            guard let name = nameTextField?.text, !name.isEmpty else {
                print("Empty name is not allowed")
                return
            }
            databaseManager.save(name: name)
            nameTextField?.text = ""
        }
    
        @IBAction func printNames(button: UIButton) {
    
            var names: String = ""
            databaseManager.fetchData { students in
                names = students.map { $0.name ?? "" }.joined(separator: "\n")
            }
    
            nameLabel?.text = names
        }
    }
    
    

    ModelObject enter image description here