Xcode: +CoreDataProperties.swift issue - iphone

I'm designing an app which is going well but I had an issue a while ago whereby I had to create a new model for CoreData because I made alterations to the Entities. I'm up to the fourth version and I had another issue with the app and I cleaned it. Now, this is what I'm getting:
The 'deleted' Attribute is set to NSDate
but after I try to build it again I get the following error:
I thought if I made alterations to the Entity Xcode would pick that up and alter any files accordingly! But that doesn't seem to be the case!
I've tried deleting the +CoreDataProperties.swift files and the 'Shopping List' swift file, recreating the 'Shopping List' swift file, under a different class name, and trying to build it again but I get the same error. This tells me its a CoreData issue, not a Swift issue. Obviously I need the attribute as NSDate but I'm not sure where to go from here!
The only way I can get the app to build is to comment out the 'deleted' attribute in the +CoreDataProperties.swift file and it runs fine.
I have the app running on a test iPhone 6 and the last time I made changes to the Entity I lost all the data I entered manually on the phone because of errors. The only way to get the app back up and running was to delete the app off the phone and reinstall it. I seriously don't want to go down that route again because I have nearly 450 various records on the phone.
If I leave the 'deleted' Attribute commented out when its uploaded to the app store, will it fail to upload, and will it fail to work correctly if the upload is successful?
I'd rather sort the issue before trying!

What you need to do is called light weight migrations. In app delegate you need to tell the app to look for the new version and create presistence store
lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/// THIS IS THE CODE YOU NEED TO ADD
let container = NSPersistentContainer(name: "NAMEGOESHERE")
let description = NSPersistentStoreDescription()
description.shouldInferMappingModelAutomatically = true
description.shouldMigrateStoreAutomatically = true
container.persistentStoreDescriptions = [description]
// End of new code
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)")
}
})
return container
This method worked for me. There are a number of tutorials out there on doing light weight migrations here and there is a stack overflow answer which is one I actually referred to when I had this problem here. By doing migrations your app shall be able to create a new persistance store and in that new store it ll change the attribute of deleted from Bool to NSdate as in the generated managedobject file. Hope this helps

Related

Getting error in realm when i try to add new property in realm object

Thread 1: Fatal error: 'try!' expression unexpectedly raised an error:
Error Domain=io.realm Code=1 "Provided schema version 0 is less than
last set version 1." UserInfo={NSLocalizedDescription=Provided schema
version 0 is less than last set version 1., Error Code=1}
Getting this error when I try to add new property in Realm
Not finding any solution for this in swiftui
That's a normal error you will receive during development as you are changing your model and properties around.
The schema version is set to 1 (or it was set to 1) and then you modified an object so you should set schema version to 2 via a migration.
From the docs
Realm Database can automatically migrate added properties, but you
must specify an updated schema version when you make these changes.
If you're just in development, you could also just delete the Realm file and the objects will be built again with schema version 1.
Please see the documentation for Realm Migrations.
We've do that a LOT during the early stages of development so we have a button in our UI that just deletes the Realm files - keeping in mind that upon app start, you cannot touch the realm file for this to work. Once you've touched it, it's 'open' and cannot be deleted through code.
func deleteRealm() {
do {
//return the config pointing to where the realm file is located - we
// keep ours in the project folder initially
let config = gGetConfig()
let isSuccess = try Realm.deleteFiles(for: config)
print("deleted realm: \(isSuccess)")
} catch let err as NSError {
print(err.localizedDescription)
}
}
Edit: Sometimes you can nil the Realm out and then delete it via code but Realm is quite stubborn and sometimes that doesn't work either.

NSPersistenceContainer returns nil?

When setting up a CoreData stack, I noticed that NSPersistenceContainer may return "nil" if the name of the model is spelled wrong.
...
let container = NSPersistentContainer(name: name)
guard container != nil else { // warning here ... see explanation below
promise(.failure(.objectModelNotFound))
return
}
In the code fragment above (which is part of utility function) the compiler complains about the guard statement with a warning: "Comparing non-optional value of type 'NSPersistentContainer' to 'nil' always returns true".
The init for the NSPersistenceContainer is declared as:
convenience init(name: String)
To summarise: If the name of the model is wrong, the code in the guard's else statement is reached, and a message in the console window says: "CoreData: error: Failed to load model named XYZ"
The question then is, is it okay for NSPersistentContainer to do so? Or maybe it was stated incorrectly in the documentation?
And if not, what is the correct way to handle the situation in code without getting a warning?
Just creating an NSPersistenceContainer does not set up the Core Data Stack. You still need to call loadPersistentStores on this container. If you look at the default stack that Xcode can create for you you can see that the default implementation allows you to check that the container is set up correctly:
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)")
}
})
And in this block you can deal with the error.
Passing in an Incorrect name comes under the category of a developer error. You should know the name of your model, that exists in your bundle, and if it doesn't exist then you have a big problem.

CKAsset in server record contains no fileURL, cannot even check for nil

I am testing a sync conflict when I save a record that contains a CKAsset (simply a JPG image) using CKModifyRecordsOperation with a save policy of .IfServerRecordUnchanged. I am getting the error CKErrorCode.ServerRecordChanged. This CKError returns me useful information for conflict resolution, including the CKRecord I tried to save, and the current server version of the record. The first is in error.userInfo[CKRecordChangedErrorClientRecordKey] the second is in error.userInfo[CKRecordChangedErrorServerRecordKey].
My problem is I am trying to access the server record's CKAsset with this code:
if let photoAsset = rec["myPhoto"] as? CKAsset {
print("PhotoAsset.fileURL: \(photoAsset.fileURL)") // BAD_ACCESS ERROR HERE
self.myPartner.photo = NSData(contentsOfURL: photoAsset.fileURL)
}
I don't get how this is possible. But after further investigating, I print out the client and server CKRecords and the server one is missing the 'path' property.
client CKAsset...myPhoto (modified) -> CKAsset: 0x7b960d90; path=~/tmp/BF185B2C-7A39-4730-9530-9797E843243Aphoto, size=373959, uploadRank=0, uploadReceipt=A92Eg1qoyPG7yrg3, UUID=3C2D5DC8-4FF5-4A81-853B-395FC1C59862, referenceSignature=<012fd149 200fc600 617e3907 88763e3e 5002abbf 5b>, flags=uploaded, wrappedEncryptionKey=, signature=<0134a297 38d52f5f 9275bfba fce5b1a8 3d6b9692 d3>
server CKAsset...myPhoto = CKAsset: 0x7be700d0; referenceSignature=<015337bd 84409893 7c014f46 36248d27 ce911dc3 7a>, size=373959, uploadRank=0, UUID=DF5D2EB4-033C-49A2-AF52-6055B5A44106, wrappedEncryptionKey=<767e7cfd d1e62110 32119ee9 f6f026b3 5bcf0cc3 8053a4de>, signature=<0134a297 38d52f5f 9275bfba fce5b1a8 3d6b9692 d3>
Notice how path=~/tmp/C706423B-A3E8-4051-A9B3-483C718BFBF5photo is missing from the server one? Can anyone explain this? To fix it I try to avoid touching the CKAsset from the server record. I would like to at least be able to check for nil. I wanted to put this out there in case it helps anyone else.
Due to the crash on accessing fileURL, this is most likely a framework bug. Probably an oversight on account of the CKRecord being buried in a dictionary. I just follow it up with a regular fetch(withRecordID:).
I'm experiencing this issue as well on iOS 11.2.1 when accessing CKAsset from serverRecord property in CKRecord. It's a little bit frustrating. A workaround is fetching the object once again via func fetch(withRecordID... and then access fileURL.
This seems like the correct behavior, not a bug.
CloudKit informed you that your write operation failed because you weren't working from the latest CKRecord and gave you a non-hydrated version of the server's current CKRecord so you could determine which fields were different from your starting point. The rest is up to you.
If CloudKit returned the fully hydrated server record in the error response for a write operation, it would potentially waste enormous amounts of bandwidth/resources.
That is why CKAssets exist: to separate the size-constrained key-value fields associated with a CKRecord from the unlimited-size binary assets that can be attached to them.

Swift NSUnarchiver Error

I get the following error when i try to unarchive a custom object
'cannot decode object of class (PhotoList) for key (root); the class may be defined in source code or a library that is not linked'
I currently have a version on the app store (v1.0, have issued an update via version TestFlight (v2.0) and this is where the error happens. The error doesn't happen on the same version builds via Xcode. Nothing has changed (that I can see!) that would have caused this.
Here is the code I have for archiving the object
let data = NSKeyedArchiver.archivedDataWithRootObject(VehicleList.instance)
NSUserDefaults.standardUserDefaults().setObject(data, forKey: "archiveName")
And here is the code I have for unarchiving the object
if let data = NSUserDefaults.standardUserDefaults().objectForKey("archiveName") as? NSData {
let photoList : PhotoList = NSKeyedUnarchiver.unarchiveObjectWithData(data) as! PhotoList
}
It turns out the issue was related to multiple targets. It seems when I duplicated targets, I swapped over the original target with another, so it was in fact a different target that couldn't unarchive the data.
So be careful when you create targets and make sure you don't mix them up! Hope this saves someone the amount of time it took me to figure this out!

executeFetchRequest:error: A fetch request must have an entity

I had a project that was working fine. It had "Core Data" checked, and had the data model all set up. I only started adding a couple entities and properties tonight. When I try to run my app now, it won't even load. It just crashes on me.
Here's the error:
'NSInvalidArgumentException', reason: 'executeFetchRequest:error: A fetch request must have an entity.'
I'm really scared because I don't have a backup of this and if I can't get it working I don't know what I'll do. :)
Thanks in advance!
EDIT:
I got fed up with my data, so I just copied a new blank xcdatamodel to my project and I'm going to start fresh. Thanks for the help!
My issue is I didn't use the same name for Entity and Class. Trivial solution to fix it is by giving them the same name.
If you are using MagicalRecored with Swift:
Make sure you use #objc directive in the Swift NSManagedObject subclass to make the class accessible to Objective-C code from the MagicalRecord library
#objc(MyEntity)
class MyEntity: NSManagedObject {
#NSManaged var myAttribute: Int16
}
After searching all over for a solution, what fixed it for me was doing a Clean/Build in Xcode.
Product->Clean, Product->Build, then try running it.
It seemed as if my data got corrupted, so I deleted my data model and the database in the iPhone simulator, and started fresh.
I had the same error.
For me, it is because I have added a new Model Version, but I did not set it as "Current Version". Careless me! To fix, select the xcdatamodel, click Design > Data Model > Set Current Version. The xcdatamodel file will then have a green tick.
Hopes that helps.
Also, make sure that your .xcdatamodeld file is in the "Copy Bundle Resources" phase of your Build Phases.
Here's what fixed it for me:
As I was converting to Swift 3, Xcode was giving me an error when declaring a new NSFetchRequest, saying that it needed a type. After adding the type, I did what anyone else would have assumed; if the request is typed, why specify an entity name? So, I removed it.
It actually was my mistake.
Swift 2.2:
let request = NSFetchRequest(entityName: "MyEntity")
When I first converted to Swift 3:
let request = NSFetchRequest<MyEntity>()
That was giving me an error. I ended up with this:
let request = NSFetchRequest<MyEntity>(entityName: "MyEntity")
And everything works fine. Personally, I'm not sure why it needs to have an entity name specified, if you're typing the request. Maybe they'll update that at some point (I hope)
i found this solution in the apple develper forum and it was exactly my problem!
the solutions is that the context must be defined inside the struct App.
not in the environment parameter
import SwiftUI
#main
struct CoreDataDemoApp: App {
private let context = CoreDataStack.context.
var body: some Scene {
WindowGroup {
ContentView()
.environment(\.managedObjectContext, context)
}
}
}
Check if,
the entity is present in the xcdatamodel file.
entity name used are same.
If you are using Swift 3 and Core Data's new stack syntax:
var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "MyAppModel")
container.loadPersistentStores(completionHandler: {
(storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
} else {
print(storeDescription)
}
})
return container
}()
Then you should be using this fetch syntax:
let request: NSFetchRequest<Client> = Client.fetchRequest()
I had this error on the first fetch after app launches when using different variations:
let request: NSFetchRequest<NSFetchRequestResult> = Client.fetchRequest()
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Client")
I did stumble across the same precise error upon taking my first steps into Core Data (and iOS 11 and Swift 4). I started off a book (sixth edition meant to target Swift 4 but presumably including some legacy stuff).
As suggested in the book my code was:
let fetchRequest = NSFetchRequest<ReminderData>()
let entity = ReminderData.entity()
fetchRequest.entity = entity
do {
let rows = try managedObjectContext.fetch(fetchRequest)
} catch {
fatalError("Unresolved error")
}
It turned out that all I got from ReminderData.entity() is nil. Not sure if I did something wrong when setting up the data model or ... Apple's docs say that NSManagedObject.entity() must not be overwritten?
Long story short, the Codegen file ReminderData+CoreDataProperties.swift did include the solution:
#nonobjc public class func fetchRequest() -> NSFetchRequest<ReminderData> {
return NSFetchRequest<ReminderData>(entityName: "ReminderDB")
}
which was all I had to use to end-up with a proper NSFetchRequest, no fiddling with the NSEntityDescription, problem gone!
let fetchRequest = NSFetchRequest<ReminderData>(entityName: "ReminderDB")
do {
let rows = try managedObjectContext.fetch(fetchRequest)
} catch {
fatalError("Unresolved error")
}
I built clean, and that didn't fix it. Then I deleted the app, and that didn't fix it. Then I built clean and deleted the app AT THE SAME TIME, and that fixed it.
Just add the same problem. I copied all my entities. Deleted the data model, recreated an empty one and pasted the entities back into the new data model. Solved my issue.
First I downloaded the app's data through the Organizer (to see what was happening) and noticed that it offered me to save it under a previous project name. This puzzled me. So I exited XCode 4.6.1, deleted the app (and its data) from my iPhone, and came back.
This time I got an error saying Cannot create an NSPersistentStoreCoordinator with a nil model. So I looked into the AppDelegate.m file and changed the URLForResource in the - (NSPersistentStoreCoordinator *) persistentStoreCoodinator method. It was set to the name of my app, and I changed it to 'Model' so as to match the name of my Model.xcdatamodeld.
It's working now.
This happened to me when I was fetching from the wrong database. My application has 3 sqlite databases, and of course 3 ManagedObjectContext instances. Well I was submitting the wrong ManagedObjectContext to a method asking it to query a table that didn't exist in the ManagedObjectContext I submitted. After using the correct ManagedObjectContext, all was good.
I think the original question/problem, and also the issue that most of these answers fixes (just in different ways) is just a real simple one:
Anytime you modify your core data (like adding an entity as you mention), you either have to delete all existing data (if you haven't published your app yet), or add a new version to your model.
Just thought I would post this answer, even though this is an older question, because this answer seems pretty obvious and so far hasn't been discussed in any of the questions or comments I read above.
You can also use setter method from CoraData ... Just do something like this...
On your CustomCoreDataManager.m
import "ObjectiveRecord.h"
call init method like this
(instancetype)init {
self = [super init];
if (self) {
[[CoreDataManager sharedManager] setModelName:#"YourModelName"];
}
return self; }
Hope this helps to someone...
Maybe you are trying to load a Database from a different/the wrong bundle?
For instance from or within a Framework?
I had this issue and solved it by loading the DB from the bundle of the related Framework. And then it all worked fine!!
Swift 4 + MagicalRecord:
let frameworkBundle = Bundle(for: AClassFromTheFramework.self)
let managedObjectModel = NSManagedObjectModel.mergedModel(from: [frameworkBundle])
MagicalRecord.setShouldAutoCreateManagedObjectModel(false)
NSManagedObjectModel.mr_setDefaultManagedObjectModel(managedObjectModel)
MagicalRecord.setupCoreDataStack(withAutoMigratingSqliteStoreNamed: "db.sqlite")
And voila !
I faced same issue, actually i was calling MyEnty instead of MyEntity so please re-check what names you have given to your entities and call the same and also check whether you are calling same attributes that you have defined like name
In my case, it was because this dropdown was not set to "Current Product Module" in the Data Model Inspector in Xcode (13.4.1):
Once I set that, it stopped crashing.
Hope this helps!