Error due to change in relationship - swift

I am getting the following error message when I changed the relationship from one-to-one to one-to-many for following relationships
eventSch?.setValue(eventDesc, forKey: "eventDec")
eventDesc.setValue(eventSch, forKey: "eventSchedule")
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unacceptable type of value for
to-many relationship: property = "eventDec"; desired type = NSSet;
given type = EventDec; value = (entity:
EventDec; id: 0x60800022bcc0
;
data: {
eventSchedule = nil;
eventStatus = 0; }).'
How do I get rid of this error?

This: eventSch?.setValue(eventDesc, forKey: "eventDec") is causing errors, because you are supplying an entity; instead you should be supplying an NSSet.
I don't know Objective-C well; however, your code should look something similar to this:
NSMutableSet* eventDescSet = [NSMutableSet set];
[eventDescSet addObject: eventDesc]; // you have your set with one item
eventSch?.setValue(eventDescSet, forKey: "eventDec")
Also, I would use more descriptive names for clarity.

There is an SQL file on your device that is based on the old version, so when the app tries to load it based on the new model it can't figure out how to read it.
[Hard solution] If you have you app already published on the appstore then you should rollback your model to what it was at the time that you published, and then make a new model with your changes.
[Easy solution] If you are the only person with the app, and you are still in development there is no reason to make a model version. Just delete form your phone (and/or the simulator) and reinstall. The SQL file based on the old version will be gone.

Related

Xcode: +CoreDataProperties.swift issue

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

Core Data commands crash ViewController even after delete

I was trying to add autosaving to my Core Data-based app and there was a line of code I added to textDidChange in a CollectionViewItem:
theNote?.updateChangeCount(NSDocumentChangeType.ChangeDone)
That gave me a lot of errors, so I commented out the line. I then went in to delete the CocoaAppCD.storedata persistent store file to make it cleaner (I'm still in early dev stages so all that goes in my persistent store is random test materials).
Now, I'm finding, Core Data commands crash my ViewController. Specifically this function:
func createNewNotebook(folderURL: NSURL)
{
let currentNotebook = Notebook(entity: sv.noteType, insertIntoManagedObjectContext:sv.context)
currentNotebook.folderURLstring = folderURL.absoluteString
let noteSet = currentNotebook.mutableSetValueForKey("contains")
print(String(noteSet))
intakeFilesFromFolder(noteSet, currentFolderURL: folderURL)
}
(Notebook and NoteEntity are the two entity types in my Core Data model.) When either the currentNotebook.folder... or let noteSet... commands run, I get these errors in my console:
Brouillon.NoteEntity folderURLstring]: unrecognized selector sent to instance 0x6080000a3a20
2016-07-24 19:27:02.622 Brouillon[8006:361665] Failed to set (contentViewController) user defined inspected property on (NSWindow): -[Brouillon.NoteEntity folderURLstring]: unrecognized selector sent to instance 0x6080000a3a20
and the WindowController is empty with no view filling it (even though these same statements had worked before I added the now-commented-out line). But if I bypass this function so the Core Data statements don't run, the views load. I would have thought that if I had anything dirty left in the database, deleting the CocoaAppCD.storedata file should have fixed it (and I keep deleting that file after every run). But it seems like something in Core Data is still mucked up for me - any ideas?
I figured this out. The problem was I had declared the wrong entity type: my sv.noteType should have been sv.notebookType, since it was a Notebook rather than a NoteEntity. (The error would have been introduced when I was creating the class instantiated as sv, as a class to hold my otherwise-duplicated code.)

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!

ExecuteFetchRequest intermittently throwing exception with same parameters. "not key value coding-compliant for the key"

EDIT Thanks to Matt's post I now understand that I should not be trying to access 'started' as an array. However, if that is the case, I would like to know why this code appears to be working in other places. It still seems to me that this should be "one-or-the-other." It should work or it shouldn't.
ORIGINAL
I'm using the same fetch request in various parts of my code to find the most recent game:
Game *lastGame = [[[CoreDataAccess managedObjectContext] fetchObjectsForEntityName:#"Game" withPredicate:#"started == started.#max"] anyObject];
'Game' is an NSManagedObject and 'started' is a date attribute. 'started' is set exactly once per object in awakeFromInsert. It is never changed after that. Game is never directly instantiated, but it has three subclasses. I have tried making Game both abstract and concrete, but neither has any effect on this problem.
I'm using an NSManagedObjectContext category to perform the fetch, as shown on cocoa with love here http://cocoawithlove.com/2008/03/core-data-one-line-fetch.html.
The error I am getting is the following:
Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. [<__NSDate 0xebb1130> valueForUndefinedKey:]: this class is not key value coding-compliant for the key #max. with userInfo {
NSTargetObjectUserInfoKey = "2010-11-06 11:16:53 GMT";
NSUnknownUserInfoKey = "#max";
}
It looks to me like the predicate might be trying to apply #max to a single NSDate, instead of all 'started' attributes in all games. I'm not sure though. I'm not very good with predicates, and it took me a lot of trial and error to make this one. I don't understand how the exact same fetch can have errors in different places, though.
The fetch is not part of an NSFetchedResultsController, but I am using a fetchedResultsController in the class where I'm getting the error. For example:
- (void)configureCell:(UITableViewCell*)cell atIndexPath:(NSIndexPath*)indexPath{
Game *game = [self.frc objectAtIndexPath:indexPath];
Game *lastGame = [[[CoreDataAccess managedObjectContext] fetchObjectsForEntityName:#"Game" withPredicate:#"started == started.#max"] anyObject]; // Sometimes we get past this line, sometimes we don't...
NSDateFormatter *format = [[NSDateFormatter alloc] init];
[format setDateFormat:#"EEE, MMM d, yyyy h:mm a"];
if (game != lastGame)
cell.detailTextLabel.text = [format stringFromDate:game.started];
else
cell.detailTextLabel.text = #"In Progress";
[format release];
...
}
and also here:
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the specified item to be editable.
Game *lastGame = [[[CoreDataAccess managedObjectContext] fetchObjectsForEntityName:#"Game" withPredicate:#"started == started.#max"] anyObject];
if (lastGame == [frc objectAtIndexPath:indexPath])
return NO;
return YES;
}
This exact fetch is performed several times in several places, for example on startup, but it only crashes in one class. As I said it is intermittent, but it seems to be sometime after I create a new Game object. The game is created in one tab, and the code above is from a second tab which shows history.
I have seen a similar error here. In that case the problem was solved by restarting the computer, which finally allowed XCode to realize that the attribute had been deleted from the model. I have tried that, and I'm still experiencing the problem. I have also tried deleting and recreating the 'started' attribute in the model. I have also read the Core Data Troubleshooting Guide, but was unable to find any help there either.
Predicates are applied to one source object at a time. If your source object does not have an array property, you can't use an array operator.
In your case, the predicate says:
Look at a given "Game". If its own
"started" property is equal to its own
"started" property with the #max KVC
array operator applied, then this
predicate will be true.
This is not what you want. The only situation where you'd use a KVC array operator in a predicate is where a property on an object is an array. e.g.
Fetch every "Season" where the "games.#max.homeTeamScore > 50" (i.e. seasons where a home team scored more than 50 in a game). This would work because the "games" property on a "Season" would be an array, so games.homeTeamScore would also be an array.
However, the "started" property on a single Game is not an array. The array you want to operate on is actually the array of all games, which is not a property of a game.
The only twisted way you could access the array of all games would be to fetch the array of all games first, then apply the array operator outside the predicate and then on the inside of the predicate only apply the equality test.
i.e. fetch all games first, then refetch with:
fetchObjectsForEntityName:#"Game" withPredicate:#"started == %#", [allGames valueForKey:#"#max.started"]
But this is not the smart thing to do either.
Ultimately, the correct way to fetch the game with the latest starting date as you're trying to do, can't be done with the single line fetch method.
You'll need to create a variant of the method that allows you to setSortDescriptors: on the fetch request (to sort by "started", descending) and then setFetchLimit:1 on the fetch request to only get first result.