Core Data NSSet returning empty array of objects - iphone

UPDATE: I had ghost entries in my database of games without players from before I implemented Players at all. It was returning those entries not the latest entries with the updated Model
I am working to get a Core Data database working and having some trouble with relationships. I'm very new to the whole thing so don't put anything past me I may no even understand the basics. But here we go anyway.
This is where I create a new Game Entity. The Players is a to-may relationship to Several Player entities that were selected and stored in an array.
Game *newGame = [NSEntityDescription insertNewObjectForEntityForName:#"Game" inManagedObjectContext:[SDDataManager dataManager].managedObjectContext];
[newGame setGameType:#"multipleChoice"];
[newGame setDate:[NSDate date]];
NSSet *playersSet = [NSSet setWithArray:players];
[newGame setPlayers:playersSet];
[newGame setCards:[NSKeyedArchiver archivedDataWithRootObject:selectedCards]];
NSError *error;
[[SDDataManager dataManager].managedObjectContext save:&error];
NSLog(#"New Game Error: %#",[error localizedDescription]);
The problem is that when I call it out of the database like this:
NSFetchRequest *requestSavedGame = [NSFetchRequest fetchRequestWithEntityName:#"Game"];
[requestSavedGame setFetchLimit:1];
NSError *error;
NSArray *loadedGame = [[SDDataManager dataManager].managedObjectContext executeFetchRequest:requestSavedGame error:&error];
NSLog(#"Load Game Error: %#",[error localizedDescription]);
Game *game = [loadedGame objectAtIndex:0];
NSLog(#"Players Set: %#",game.players);
NSLog(#"Players: %#",[game.players allObjects]);
The Players: is empty?? It returns this exactly:
Players Set: Relationship 'players' fault on managed object (0xd023b70) <Game: 0xd023b70> (entity: Game; id: 0xd023180 <x-coredata://E6A82377-31D2-4D11-B890-B3FDC5A03E0E/Game/p1> ; data: {
cards = <62706c69 73743030 d4010203 0405086e 6f542474 6f705824 6f626a65 63747358 24766572 73696f6e 59246172 63686976 6572>;
currentPlayer = 0;
date = "2012-03-27 18:20:07 +0000";
gameType = multipleChoice;
players = "<relationship fault: 0xd01fd60 'players'>";
})
Players: ( )
I have no understanding why the players is a full array, then a full set when it goes in but when it comes out the [set allobjects] returns an empty array...

I would suggest you to use valueForKey for whatever key.
In core data fault is not an error, it means you are trying to access from core data which does not exist. and i would say you should use setPropertiesToFetch which specifies which properties should be returned by the fetch.

The message saying that it is a fault does not mean that it is empty. It simply means that the data has not been loaded from the database. If you access it like normal, you should see your data there. Try this and see what it says:
NSLog(#"Players count: %i", [game.players count]);
Read about faults here: Core Data Programming Guide - Faulting and Uniquing

Related

The model used to open the store is incompatible with the one used to create the store, apple store release version [duplicate]

I created a Core Data model in xcode 3.2 and after upgrading in Xcode 4.2, I then added a new entity of the NSManagedObject subclass (refer to the new entity).
First thing, it looks weird because it's not in the same group as the old one. Here is the picture on my xcode 4.2 (AlkitabDB is the one i created in xcode 3.2, EndeDB is the new one from current xcode version(4.2):
Second thing, I let it as it is, then I accessed the second entity (the new one) the same way as the first entity (the old one), and the error as titled appears.
Here is the error:
2012-01-16 21:13:38.496 iHuria[55953:207] Unresolved error Error Domain=NSCocoaErrorDomain Code=134100 "The operation couldn’t be completed. (Cocoa error 134100.)" UserInfo=0x8829cd0 {metadata=<CFBasicHash 0x882a370 [0x1839b38]>{type = immutable dict, count = 7,
entries =>
2 : <CFString 0x8829b90 [0x1839b38]>{contents = "NSStoreModelVersionIdentifiers"} = <CFArray 0x8829ff0 [0x1839b38]>{type = immutable, count = 0, values = ()}
4 : <CFString 0x8829bc0 [0x1839b38]>{contents = "NSPersistenceFrameworkVersion"} = <CFNumber 0x8829770 [0x1839b38]>{value = +320, type = kCFNumberSInt64Type}
6 : <CFString 0x8829bf0 [0x1839b38]>{contents = "NSStoreModelVersionHashes"} = <CFBasicHash 0x882a080 [0x1839b38]>{type = immutable dict, count = 1,
entries =>
0 : <CFString 0x882a010 [0x1839b38]>{contents = "AlkitabDB"} = <CFData 0x882a030 [0x1839b38]>{length = 32, capacity = 32, bytes = 0xd02ac5f8be6ab0b39add450aca202ac0 ... 3d45d462998d2ccd}
}
7 : <CFString 0x10e3aa8 [0x1839b38]>{contents = "NSStoreUUID"} = <CFString 0x8829e60 [0x1839b38]>{contents = "4F2EE7FF-463B-4055-BBED-8E603CDBDF59"}
8 : <CFString 0x10e3948 [0x1839b38]>{contents = "NSStoreType"} = <CFString 0x10e3958 [0x1839b38]>{contents = "SQLite"}
9 : <CFString 0x8829c40 [0x1839b38]>{contents = "NSStoreModelVersionHashesVersion"} = <CFNumber 0x6b1c7c0 [0x1839b38]>{value = +3, type = kCFNumberSInt32Type}
10 : <CFString 0x8829c70 [0x1839b38]>{contents = "_NSAutoVacuumLevel"} = <CFString 0x882a0c0 [0x1839b38]>{contents = "2"}
}
, reason=The model used to open the store is incompatible with the one used to create the store}, {
metadata = {
NSPersistenceFrameworkVersion = 320;
NSStoreModelVersionHashes = {
AlkitabDB = <d02ac5f8 be6ab0b3 9add450a ca202ac0 ebd1e860 cbb578c2 3d45d462 998d2ccd>;
};
NSStoreModelVersionHashesVersion = 3;
NSStoreModelVersionIdentifiers = (
);
NSStoreType = SQLite;
NSStoreUUID = "4F2EE7FF-463B-4055-BBED-8E603CDBDF59";
"_NSAutoVacuumLevel" = 2;
};
reason = "The model used to open the store is incompatible with the one used to create the store";
}
I looked for the solution before and discovered that I should remove the appliation from simulator and rerun the app, and it didn't work.
Does anyone know a solution for this issue?
Please help.
Deleting the app is sometimes not the case! Suggest, your app has already been published! You can't just add new entity to the data base and go ahead - you need to perform migration!
For those who doesn't want to dig into documentation and is searching for a quick fix:
Open your .xcdatamodeld file
click on Editor
select Add model version...
Add a new version of your model (the new group of datamodels added)
select the main file, open file inspector (right-hand panel)
and under Versioned core data model select your new version of data model for current data model
THAT'S NOT ALL ) You should perform so called "light migration".
Go to your AppDelegate and find where the persistentStoreCoordinator is being created
Find this line if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
Replace nil options with #{NSMigratePersistentStoresAutomaticallyOption:#YES, NSInferMappingModelAutomaticallyOption:#YES} (actually provided in the commented code in that method)
Here you go, have fun!
P.S. This only applies for lightweight migration. For your migration to qualify as a lightweight migration, your changes must be confined
to this narrow band:
Add or remove a property (attribute or relationship).
Make a nonoptional property optional.
Make an optional attribute nonoptional, as long as you provide a default value.
Add or remove an entity.
Rename a property.
Rename an entity.
For Swift 4
coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true])
Remove the app from the simulator and perform a clean on your project. That should clear those issues up. Make sure that you are not running in the debugger when you delete the app or else it won't actually delete it properly.
If you want to be sure its gone, check this directory Users/INSERT_YOUR_USER_HERE/Library/Application Support/iPhone Simulator/ for your app's folder, under the version you're running.
Note: This is for development only. For production, you need to implement some sort of migration. Google "Core Data Migration", with lightweight migration being the simplest.
Just add Options attribute while creating persistentStoreCoordinator in AppDelegate.m file for the core data method as below
OBJECTIVE-C
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil)
{
return _persistentStoreCoordinator;
}
NSLog(#"persistentStoreCoordinator___");
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"MyApp.sqlite"];
NSMutableDictionary *options = [[NSMutableDictionary alloc] init];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
NSLog(#"persistentStoreCoordinator___2");
return _persistentStoreCoordinator;
}
SWIFT
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
// The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added 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.
// Create the coordinator and store
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite")
var failureReason = "There was an error creating or loading the application's saved data."
// MAIN LINE OF CODE TO ADD
let mOptions = [NSMigratePersistentStoresAutomaticallyOption: true,
NSInferMappingModelAutomaticallyOption: true]
do {
try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: mOptions)
} catch {
// Report any error we got.
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = failureReason
dict[NSUnderlyingErrorKey] = error as NSError
let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
// Replace this with code to handle the error appropriately.
// abort() 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.
NSLog("Unresolved error \(wrappedError), \(wrappedError.userInfo)")
abort()
}
return coordinator
}
It had solved my problem..
Answer : Remove the app from the Simulator , Perform a Clean and Re-Build your Project.
Note : Whenever you perform changes to the Core Data definition, Delete the app installed on the Physical Device or Simulator, Clean the Project and Re-Build again.
Yes. Once you delete app on physical device and rebuild it works.
For swift, in AppDelegate.swift find the line
try coordinator!.addPersistentStoreWithType(NSXMLStoreType, configuration: nil, URL: url, options: nil )
and replace it with
try coordinator!.addPersistentStoreWithType(NSXMLStoreType, configuration: nil, URL: url, options: [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true])
I just spent several days fighting this error, as well as mergedModelFromBundles crashes, and getting the "Can't merge models with two different entities named *" error.
It turns out the root problem was that Xcode doesn't remove old resources from devices and I had old versions of my data model (.mom files) that were causing conflicts. This is why deleting the app fixed the problem on one of my devices.
After finding this blog post via another SO answer I made my app more tolerant of old models by changing this line which looks for ALL .mom files:
NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
to this, which only looks in the Filters directory:
NSString *path = [[NSBundle mainBundle] pathForResource:#"Filters" ofType:#"momd"];
NSURL *momURL = [NSURL fileURLWithPath:path];
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:momURL];
I used recursivePathsForResourcesOfType from this so question: to help figure this out by logging all of the .mom files in the app:
NSArray *momPaths = [self recursivePathsForResourcesOfType:#"mom" inDirectory:[[NSBundle mainBundle] resourcePath]];
NSLog(#"All .mom files:%#",momPaths);
I also used iExplorer to look at the extraneous .mom files (I didn't try deleting them yet).
The method below was also helpful. It showed that an entity was in the merged model returned by [psc managedObjectModel] that didn't exist any more in any of my models or in the store itself. This was what let me to believe an old model was being cached on the device itself that clean building didn't remove. The method logs each entity that is the same, been changed, or added to, or removed from the model. (written with this SO answer as a starting point):
- (BOOL)comparePersistentStore:(NSPersistentStoreCoordinator *)psc withStoreURL: (NSURL *)storeURL {
NSError *error = nil;
// Get the entities & keys from the persistent store coordinator
NSManagedObjectModel *pscModel = [psc managedObjectModel];
NSDictionary *pscEntities = [pscModel entitiesByName];
NSSet *pscKeys = [NSSet setWithArray:[pscEntities allKeys]];
//NSLog(#"psc model:%#", pscModel);
//NSLog(#"psc keys:%#", pscKeys);
NSLog(#"psc contains %d entities", [pscModel.entities count]);
// Get the entity hashes from the storeURL
NSDictionary *storeMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType
URL:storeURL
error:&error];
NSDictionary *storeHashes = [storeMetadata objectForKey:#"NSStoreModelVersionHashes"];
//NSLog(#"store metadata:%#", sourceMetadata);
NSLog(#"store URL:%#", storeURL);
NSLog(#"store NSStoreUUID:%#", [storeMetadata objectForKey:#"NSStoreUUID"]);
NSLog(#"store NSStoreType:%#", [storeMetadata objectForKey:#"NSStoreType"]);
NSSet *storeKeys = [NSSet setWithArray:[storeHashes allKeys]];
// Determine store entities that were added, removed, and in common (to/with psc)
NSMutableSet *addedEntities = [NSMutableSet setWithSet:pscKeys];
NSMutableSet *removedEntities = [NSMutableSet setWithSet:storeKeys];
NSMutableSet *commonEntities = [NSMutableSet setWithSet:pscKeys];
NSMutableSet *changedEntities = [NSMutableSet new];
[addedEntities minusSet:storeKeys];
[removedEntities minusSet:pscKeys];
[commonEntities minusSet:removedEntities];
[commonEntities minusSet:addedEntities];
// Determine entities that have changed (with different hashes)
[commonEntities enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) {
NSData *storeHash = [storeHashes objectForKey:key];
NSEntityDescription *pscDescrip = [pscEntities objectForKey:key];
if ( ! [pscDescrip.versionHash isEqualToData:storeHash]) {
if (storeHash != nil && pscDescrip.versionHash != nil) {
[changedEntities addObject:key];
}
}
}];
// Remove changed entities from common list
[commonEntities minusSet:changedEntities];
if ([commonEntities count] > 0) {
NSLog(#"Common entities:");
[commonEntities enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) {
NSData *storeHash = [storeHashes objectForKey:key];
NSEntityDescription *pscDescrip = [pscEntities objectForKey:key];
NSLog(#"\t%#:\t%#", key, pscDescrip.versionHash);
}];
}
if ([changedEntities count] > 0) {
NSLog(#"Changed entities:");
[changedEntities enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) {
NSData *storeHash = [storeHashes objectForKey:key];
NSEntityDescription *pscDescrip = [pscEntities objectForKey:key];
NSLog(#"\tpsc %#:\t%#", key, pscDescrip.versionHash);
NSLog(#"\tstore %#:\t%#", key, storeHash);
}];
}
if ([addedEntities count] > 0) {
NSLog(#"Added entities to psc model (not in store):");
[addedEntities enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) {
NSEntityDescription *pscDescrip = [pscEntities objectForKey:key];
NSLog(#"\t%#:\t%#", key, pscDescrip.versionHash);
}];
}
if ([removedEntities count] > 0) {
NSLog(#"Removed entities from psc model (exist in store):");
[removedEntities enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) {
NSData *storeHash = [storeHashes objectForKey:key];
NSLog(#"\t%#:\t%#", key, storeHash);
}];
}
BOOL pscCompatibile = [pscModel isConfiguration:nil compatibleWithStoreMetadata:storeMetadata];
NSLog(#"Migration needed? %#", pscCompatibile?#"no":#"yes");
return pscCompatibile;
}
usage: called before adding each store to NSPersistentStoreCoordinator :
[self comparePersistentStore:self.psc withStoreURL:self.iCloudStoreURL];
_iCloudStore = [self.psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:self.iCloudStoreURL
options:options
error:&localError];
Every time you making change to the Core Date definition, you should delete the apps installed on the physical device or simulator.
Stop app from running.
Delete app on simulator.
Product - > Clean
Build, run.
The simplest solution that worked for me in Swift 2.1, Xcode 7 is :
Delete the app from the Simulator ( Cmd + Shift + H to go to the Home Screen. Long Press the app, Click cross, just the usual way you delete an app from your phone)
Cmd + Shift + H again to stop the dancing of apps
Go back to your project and rerun
I had this issue while writing/reading from Core Data with 2 entities set up. Deleting the app and rerunning the program fixed the issue
I just deleted [Simulator App Folder]/Document/*.sqlite file after making changes in entities and it worked.
And of course, .sqlite file contains all stored data and structures which will be lost.
Please Delete a application from simulator and clean a code and run .its work fine .do it may be its help YOU.
If you are using Swift.
Follow the answer by #Stas and insert options, in place of nil, in your App Delegate:
let myOptions = [NSMigratePersistentStoresAutomaticallyOption: true,
NSInferMappingModelAutomaticallyOption: true]
if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: myOptions, error: &error) == nil {
Try "Reset Content & Settings" in the simulator. Worked for me after deleting app and Clean build
I experienced the same issue with my app (not yet released in App Store).
Here's how I fixed it:
Run Clean (Cmd+Shift+K)
Restart iOS Simulator
iOS Simulator -> Reset Content and Settings (from navbar)
(3) was the step that finally got it to run properly. Hope this helps!
In my case, I had two persistent stores, one local store for user specific data, and one CoreData+CloudKit store for common data that syncs automatically with iCloud. Thus the data model has two configurations, and the entities are assigned to both configurations as required.
Due to a bug during development, I tried to store an entity that was no longer assigned to any configuration. So when the context was saved, CoreData realized the incompatibility, and crashed with this error.
Of course, deleting the app does not help in such a case. One has to ensure that only assigned entities are stored in a persistent store.
Although sometimes you can just remove the app from the device when changing schema in managed object model, in some scenarios this is not possible e.g. because you already published your app with an old schema.
If this is the case, you have to take care of migrating old data to the new schema:
Core Data Model Versioning and Data Migration
You'll need to migrate the Core Data model using migration. Any time you change the model, you make it incompatible without versioning. Strap yourself in, it's a bit of a hairy topic.
http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/CoreDataVersioning/Articles/Introduction.html
If you make changes to your Core Data model, you have to provide a migration policy that tells Core Data how to adopt existing persisted objects (that your users created with the currently released version) to the new model.
For some scenarios, Core Data is able to automatically infer the mapping from the old model to the new one. For more complex changes, you might have to implement some logic that performs the migration.
Details can be found in the Core Data Model Versioning and Data Migration Programming Guide.
Update
This answer here on Stack Overflow covers the basics of Core Data's lightweight migration and also has some code to get you started.
First, the only things that should be in the xcdatamodeld bundle are xcdatamodel files. Your subclasses should NOT be in the xcdatamodeld. Move those out of there. There is a fair chance they are confusing the compiler.
Second, the error indicates that Core Data cannot find your model. Have you created data and then touched the model? If so you are in an inconsistent state and need to fix that either by deleting the data (which Philippe suggested) or by rolling your changes of the model BACK.
This issue generally occurs due to incompatibility between the version on which DB has been created. General approach to this problem is to delete the app and reinstall it. But in your mentioned case the version of DB are completely different on Xcode 3.2 and 4.2. So better use same version of Xcode for DB.
I was getting the error but the reason I was getting the error was because of the following.
I originally had one Entity named "Entry" and had one row saved for that entity in the database. I then added another Entity named "Person" and after adding that went to build and got the error. So I solved the issue by deleting "Person" Entity and then building the app, deleted the row that was in "Entry" and then closed the application. I then deleted the app entirely off my phone and then did a rebuild and it worked fine. Not sure which step corrected the problem (the deletion of the row or the app), but hopefully if you're looking for a solution this will help. :)
Edit: Oh and if you worried about deleting your new Entity (in my case "Person") to build the app again remember you can get it back afterwards by using CMD+Z!
I had this problem - I first reset my simulator and then clean the project and rebuild. And then it works.
When you change core data, ( adding a field to table , removing field etc ), the sqlite file in applications document folder needs to be in sync with your schema.
This file is not overwritten by default, this file needs to be regenerated.
Follow these steps:
Go to the folder pointed by NSURL. (This path can be found in exception message generated by application before crashing.)
example : /Users//Library/Application Support/iPhone Simulator//Applications//Documents
remove or rename the sqlite file
Clean and Rerun the application
Rerunning application would generate a new sqlite file.
This will make sure that the schema and Xcode are in sync.
This may help some people but may not answer the question. In my case, the problem was solved because I forgot to add the model to the correct configuration. See the screenshot attached. All the models are added to the default configuration, but my application uses the private configuration. Drag and drop your model from the default configuration to the correct configuration.
iOS Simulator -> Reset Contents and Settings...
Worked for me
iOS Simulator -> Reset Contents and Settings... -> Reset
Works on iOS9 (xcode 7.1) as well

How to Efficiently Reset Attributes in a Core Data Entity

My app uses Core Data and has an attribute called 'beenSeen'. When a user refreshes the app, all 'beenSeen' values of 1 are changed to 0. On an iPod Touch 2nd gen with over 2000 objects, refreshing takes over a minute. My code looks like this:
for (Deck *deck in self.deckArray) {
if ([deck.beenSeen isEqualToNumber:[NSNumber numberWithInt:1]]) {
[deck setBeenSeen:[NSNumber numberWithInt:0]];
[self.managedObjectContext save:&error];
}
}
I'm also considering deleting the sqlite file and having an alert ask the user to restart the app themselves. Doing that sure is a whole lot quicker than what I have now. Is there a quicker way to refresh an entity? Could I have a 'backup' entity and copy it over? Thanks for any help.
Hm. The first optimization I'd suggest would be
for (Deck *deck in self.deckArray) {
if ([deck.beenSeen isEqualToNumber:[NSNumber numberWithInt:1]]) {
[deck setBeenSeen:[NSNumber numberWithInt:0]];
}
}
[self.managedObjectContext save:&error];
I suspect it might speed things up to do one big context save, instead of 2,000 little ones.
The second suggestion would be to try getting rid of the if test – if the majority of your beenSeen values are changing from 1 to 0, and the others are already 0, then you might as well just set all of them to 0 and save the time of checking each one individually. (On the other hand, if there are 10,000 objects and you're resetting 2,000 of them, then getting rid of the test might not be optimal.)
for (Deck *deck in self.deckArray) {
[deck setBeenSeen:[NSNumber numberWithInt:0]];
}
[self.managedObjectContext save:&error];
}
The third suggestion would be to think about implementing this another way – for instance, your deck object could implement a lastSeen attribute, storing the date and time when the deck was last seen, and then instead of doing a mass reset (and writing 2,000 Core Data rows) you could just test each deck's lastSeen date and time against the timestamp of the last user refresh.
Try this, First, filter the array using a predicate:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"beenSeen == %#",
[NSNumber numberWithInt:1]];
NSArray* filtered = [self.deckArray filteredArrayUsingPredicate:predicate];
Now set the new value:
[filtered setValue:[NSNumber numberWithInt:0] forKeyPath:#"beenSeen"];
Finally save the context:
[self.managedObjectContext save:&error];
Hope this helps :)

Core data only storing last object of JSON feed

I´m using Core Data as local storage in my app. I´ve set it up properly and made subclasses of NSManagedObject for each entity. However, when I´m trying to insert values into my store, it only inserts the last object from my JSON feed.
res = [JSONHandler requestJSONResponse:jsonString];
shows = [res valueForKeyPath:#"Show.Name"];
NSUInteger showIndex = 0;
for(NSString *showName in shows){
showObject = [NSEntityDescription insertNewObjectForEntityForName:#"Show" inManagedObjectContext:managedObjectContext_];
showObject.name = showName;
showObject.iD = [[res valueForKeyPath:#"Show.Id"]objectAtIndex:showIndex];
showObject.desc = [[res valueForKeyPath:#"Show.Description"]objectAtIndex:showIndex];
showObject.activityType = [[res valueForKeyPath:#"Show.ActivityType"]objectAtIndex:showIndex];
showIndex++;
}
This only stores the last object from my JSON feed. Any idea why?
EDIT: It works fine when I do this:
res = [JSONHandler requestJSONResponse:jsonString];
shows = [res valueForKeyPath:#"Show.Name"];
NSUInteger index = 0;
for(NSString *showName in shows){
show = [NSEntityDescription insertNewObjectForEntityForName:#"Show" inManagedObjectContext:managedObjectContext_];
[show setValue:showName forKey:#"name"];
[show setValue:[[res valueForKeyPath:#"Show.Id"]objectAtIndex:index] forKey:#"iD"];
[show setValue:[[res valueForKeyPath:#"Show.Description"]objectAtIndex:index] forKey:#"desc"];
[show setValue:[[res valueForKeyPath:#"Show.ActivityType"]objectAtIndex:index] forKey:#"activityType"];
index++;
}
It´s basically the same thing, isn´t it? But I want to use subclasses of NSManagedObject instead of doing like I did above. Because in the snippet above show is NSManagedObject *show instead of what it should be: Show *show.
How many shows are there? You can find this by doing: NSLog(#"Number of shows: %d.", shows.count);, assuming that shows is an NSArray. It could be that your Core Data code is fine and the JSON parsing itself is at fault.
EDIT: Also, are you correctly saving the changes to the persistent store?
Usually when you see just one of several objects being saved like this, the problem is that a relationship that should be to-many is improperly set as to-one. No matter how many objects you try to add to the relationship, only the last one is set because the relationship can hold only one value.
I think in this circumstance the problem is most likely in the code of the custom subclass instead of the data model itself given that the data model works with generic NSManagedObjects.

Searching for an id in Core Data

I am getting some unexpected behavior with CoreData and NSPredicate. In a large database population I have different Managed Objects relating to one-another. However, I have a problem with the following. When giving an id (NSNumber, given as NSString to this function) I don't get a result unless I save the whole context first. I don;t want to do that as it takes too much time (as it is a large set of data). The code is:
- (DOSite *) findSite:(NSString *) siteId {
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"(id = %#)", siteId];
[NSFetchedResultsController deleteCacheWithName:nil];
[[self fetchedResultsController].fetchRequest setPredicate:predicate];
NSError *fetchError;
if (![[self fetchedResultsController] performFetch:&fetchError]) {
// Handle the error.
// This is a serious error and should advise the user to restart the application
NSLog(#"Fetching data error: %#", [fetchError localizedDescription]);
}
if([[[self fetchedResultsController] fetchedObjects] count] == 0){
return NULL;
}
return (DOSite *)[[[self fetchedResultsController] fetchedObjects] objectAtIndex:0];
}
So when I add an x number of items (using +[NSEntityDescription insertNewObjectForEntityForName:inManagedObjectContext:]) doing a search on all items return the right amount of items.
When searching for a string (e.g.predicateWithFormat:#"(name LIKE %#)") I get positive results, but when using the above code predicateWithFormat:#"(id = %#) I get zero results.
The only way I can get results is to save the whole context and then perform the fetchRequest, then suddenly it works.
So there must be something small I do wrong in searching for the id, I just seem to be blind to find it and spend two days at it now to narrow it down to this point. Is there anybody who can give me some advice on this?
This may not work, but have you tried using a name more complex than "id" in your entity (like "SiteID")? Sometimes very short names overlap with other system properties and it causes odd issues.
The problem was that I gave a NSString to the predicate as outlined above. When changing that to an int (ie predicateWithFormat:#"(id == %i)") it works fine for some reason.

iPhone SDK Core Data relationships problem

I'm having a problem with relationships between to entities in Core Data. I'm parsing some JSON and adding the entities:
if ([hourSets isKindOfClass:[NSArray class]]) { // check to see that we have got some hours back
for (NSDictionary *hourSet in hourSets) {
Hourset *thisHourSet = (Hourset *)[NSEntityDescription
insertNewObjectForEntityForName:#"Hourset"
inManagedObjectContext:managedObjectContext];
[thisHourSet setStartDate:[hourSet objectForKey:#"start_date"]];
[thisHourSet setEndDate:[hourSet objectForKey:#"end_date"]];
[record addHoursetsObject:thisHourSet];
}
}
...and then later trying to grab them again:
NSSet *hourSets = [self.listing valueForKeyPath:#"hoursets.hourset"];
NSLog(#"There are %# hourSets", [hourSets count]);
I'm getting Program received signal: “EXC_BAD_ACCESS”. when trying to access that hourSets NSSet in any way, including just counting the items in it.
Any suggestions? Pretty stumped. Thanks!
I am inferring your entity graph here but:
[self.listing valueForKeyPath:#"hoursets.hourset"]
... translates to a keypath of listing.hoursets.hourset which does not appear to return a set. Both the first and last elements are singular and therefore by convention not sets.
I would suggest logging the class of the return to confirm what, if anything, you're getting back.
Update:
(Forehead slap) The problem is actually the log statement itself. It should be:
NSLog(#"There are %d hourSets", [hourSets count]);
... because count returns an NSUInteger.