How can I test if the core data database is empty?
I tried:
NSIndexPath *path1 = [NSIndexPath indexPathForRow:0 inSection:0];
NSManagedObject *managedObject = [self.fetchedResultsController objectAtIndexPath:path1];
if([[managedObject valueForKey:#"date"] description]!=nil){SOMEFUNCTION}else{SOMEFUNCTION}
Thanks
you have to create a fetchrequest for each entity you use in core data. if the fetchrequest returns without results you don't have objects of this entity stored in your core data.
- (BOOL)coreDataHasEntriesForEntityName:(NSString *)entityName {
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:self.managedObjectContext];
[request setEntity:entity];
[request setFetchLimit:1];
NSError *error = nil;
NSArray *results = [self.managedObjectContext executeFetchRequest:request error:&error];
if (!results) {
LogError(#"Fetch error: %#", error);
abort();
}
if ([results count] == 0) {
return NO;
}
return YES;
}
not perfect I admit but it works
my code:
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:0];
int fufu = [sectionInfo numberOfObjects];
if(fufu!=0){DATABASE IS NOT EMPTY}else{DATABASE IS EMPTY}
if someone know something more efective pls post it
I have these two methods implemented in my appDelegate:
- (NSString *)applicationDocumentsDirectory
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
return basePath;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (persistentStoreCoordinator != nil)
return persistentStoreCoordinator;
NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: #"YourApp.sqlite"]];
NSLog(#"storeURL: %#", storeUrl);
NSError *error;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
NSDictionary * options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error])
{
/*
Replace this implementation 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. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
Typical reasons for an error here include:
* The persistent store is not accessible
* The schema for the persistent store is incompatible with current managed object model
Check the error message to determine what the actual problem was.
*/
}// if
return persistentStoreCoordinator;
}
The storeUrl prints the path to the sqlite database.
If you open this path with a sqlite manager, you're able to see the content of your sql database. I use this SQLite Manager to analyze sqlite databases: SQLite Manager
(You can only use this method on the simulator)
Related
I am a novice Objective-C programmer and core data user. This is my first time using core data. What I am trying to do is put entities in a core data database and then retrieve and edit them in another View Controller.
Here is the code in my ViewController.m:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *documentsDirectory = [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject];
NSString *documentName = #"myDocument";
NSURL *url = [documentsDirectory URLByAppendingPathComponent:documentName];
UIManagedDocument *document = [[UIManagedDocument alloc]initWithFileURL:url];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:[url path] ];
if(fileExists)
{
[document openWithCompletionHandler:^(BOOL success){
if(!success) NSLog(#"Error (this isn't printed)");
}];
}
else
{
[document saveToURL:url forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success){
if(!success) NSLog(#"Error (this isn't printed)");
}];
NSManagedObjectContext *context = document.managedObjectContext;
QuestionResponse *question1 = [NSEntityDescription insertNewObjectForEntityForName: #"QuestionResponse" inManagedObjectContext: context];
QuestionResponse *question2 = [NSEntityDescription insertNewObjectForEntityForName: #"QuestionResponse" inManagedObjectContext: context];
QuestionResponse *question3 = [NSEntityDescription insertNewObjectForEntityForName: #"QuestionResponse" inManagedObjectContext: context];
QuestionResponse *question4 = [NSEntityDescription insertNewObjectForEntityForName: #"QuestionResponse" inManagedObjectContext: context];
question1.question = #"What is your favorite food?";
question2.question = #"Who is your favorite fictional character?";
question3.question = #"Name someone who loves you:";
question4.question = #"What is your favorite place (real or fictional)?";
question1.order = [NSNumber numberWithInt:1];
question2.order = [NSNumber numberWithInt:2];
question3.order = [NSNumber numberWithInt:3];
question4.order = [NSNumber numberWithInt:4];
question1.group = [NSNumber numberWithInt:1];
question2.group = [NSNumber numberWithInt:1];
question3.group = [NSNumber numberWithInt:2];
question3.group = [NSNumber numberWithInt:2];
question1.display = [NSNumber numberWithBool:NO];
question2.display = [NSNumber numberWithBool:NO];
question3.display = [NSNumber numberWithBool:NO];
question4.display = [NSNumber numberWithBool:NO];
NSFetchRequest* request2 = [NSFetchRequest fetchRequestWithEntityName:# "QuestionResponse"];
NSError* error2 = nil;
NSArray* results = [context executeFetchRequest:request2 error:&error2];
if (!results || !results.count){
NSLog(#"No elements (this isn't printed)");
}
if(results.count == 4)
{
NSLog(#"We have four entities (this is what is printed)");
}
}
}
In my AnswerViewController.m this is the code:
- (IBAction)answerQuestion1:(id)sender {
//File creation begins here (same as in View Controller)
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *documentsDirectory = [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject];
NSString *documentName = #"myDocument";
NSURL *url = [documentsDirectory URLByAppendingPathComponent:documentName];
UIManagedDocument *document = [[UIManagedDocument alloc]initWithFileURL:url];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:[url path] ];
if(fileExists)
{
[document openWithCompletionHandler:^(BOOL success){
if(!success) NSLog(#"Error");
}];
NSLog(#"File Exists (this is printed)");
}
else
{
[document saveToURL:url forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success){
if(!success)NSLog(#"There has been a problem (this isn't printed)");
}];
}
NSManagedObjectContext *context = document.managedObjectContext;
//File Creation ends here
NSError *error = nil;
NSFetchRequest* request2 = [NSFetchRequest fetchRequestWithEntityName:# "QuestionResponse"];
NSError* error2 = nil;
NSArray* results = [context executeFetchRequest:request2 error:&error2];
if (!results || !results.count){
NSLog(#"No entities (this is what is printed");
}
else
{
NSLog(#"Some entities (this isn't printed)");
}
}
In my ViewController.m the core data has four elements but when I try to access them in AnswereViewController.m there is nothing in core data. Why is this happening and how can I access my elements from AnswereViewController.m?
In order to use CoreData successfully, you have to first understand the flow of it. In essence, CoreData can be broken down into two main parts:
the database (so the .sqlite file itself)
the persistent store coordinator (henceforth known as psc)
What you have done so far in ViewController.m is that you have told the compiler to insert your 4 objects into your managedObjectContext. This gets done on a psc level. The psc acts like a scratchpad for all of your database changes. Until you actually tell it to save it, it will only live in the psc and not in your .sqlite file. What you need to do then is to call:
[context save:&error2]
This will tell the compiler to push your current status of the psc into the database so it persists.
I hope this helps you.
I can't update objects in my database using core data, this my function :
- (void) saveItem:(NSDictionary*)dico {
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Item"
inManagedObjectContext:managedObjectContext];
Item *item =(Item *)[entity ReadSingleForKey:#"identifier"
value:[dico valueForKey:#"identifier"]
inContext:managedObjectContext];
if (!item) {
item = [[[NSManagedObject alloc] initWithEntity:entity
insertIntoManagedObjectContext:managedObjectContext] autorelease];
item.identifier = [dico valueForKey:#"identifier"];
}
item.title = [dico valueForKey:#"title"];
NSError *error = nil;
if (![managedObjectContext save:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}else{
NSLog(#"No error found.");
}
}
Even if "item" is not nil the object in the database doesn't change & I got always "No error found.".
- (NSManagedObject *) ReadSingleForKey:(NSString *) key
value:(id) value inContext:(NSManagedObjectContext *) context{
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:self];
[request setPredicate:[NSPredicate predicateWithFormat:#"%K = %#", key, value]];
[request setFetchLimit:1];
NSError *error;
NSArray *arr = [context executeFetchRequest:request error:&error];
if (arr && [arr count]) {
return [arr objectAtIndex:0];
}
return nil;
}
Any idea ??
There are several problems with your code that make it difficult to determine the error.
1) No error handling.
2) Obscure private method ReadSingleForKey - what does it return?
3) item defined as type Item and as different type NSManagedObject in same method.
Put in NSLog statements or breakpoints to examine the values of dico and item. You will soon find the place where you go wrong.
Another potential source of this error is how you read the data from the database later. For now I am assuming that this is working correctly.
The problem was in my Item class :
I was using #synthesize instead of #dynamic
I added a new model version, and I set the core data model to use that new version, but I get this error when the application tries to start.
"The managed object model version used to open the persistent store is incompatible with the one that was used to create the persistent store."
I'm guessing the problem is that the current persistent store is the old version of the model. Is there a way to just delete it so it makes a new one? I don't care about saving any of that data.
You have to migrate between versions. According to Apple's docs, if the changes are simple, you can do lightweight migration.
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreDataVersioning/Articles/vmLightweight.html#//apple_ref/doc/uid/TP40008426-SW1
Adding these options to the NSPersistentStoreCoordinator seemed to work.
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
NSURL *url = [applicationFilesDirectory URLByAppendingPathComponent:#"YOURAPP.storedata"];
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSXMLStoreType configuration:nil URL:url options:options error:&error]) {
[[NSApplication sharedApplication] presentError:error];
[persistentStoreCoordinator release], persistentStoreCoordinator = nil;
return nil;
}
return persistentStoreCoordinator;
In answer to your question, "Is there a way to delete it so it just makes a new one ?"
Yes.
Just change the persistentStoreCoordinator getter in your App Delegate as follows:
- (NSPersistentStoreCoordinator *) persistentStoreCoordinator {
if (persistentStoreCoordinator) return persistentStoreCoordinator;
NSManagedObjectModel *mom = [self managedObjectModel];
if (!mom) {
NSAssert(NO, #"Managed object model is nil");
NSLog(#"%#:%s No model to generate a store from", [self class], (char *)_cmd);
return nil;
}
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *applicationSupportDirectory = [self applicationSupportDirectory];
NSError *error = nil;
if ( ![fileManager fileExistsAtPath:applicationSupportDirectory isDirectory:NULL] ) {
if (![fileManager createDirectoryAtPath:applicationSupportDirectory withIntermediateDirectories:NO attributes:nil error:&error]) {
NSAssert(NO, ([NSString stringWithFormat:#"Failed to create App Support directory %# : %#", applicationSupportDirectory,error]));
NSLog(#"Error creating application support directory at %# : %#",applicationSupportDirectory,error);
return nil;
}
}
NSURL *url = [NSURL fileURLWithPath: [applicationSupportDirectory stringByAppendingPathComponent: #"storedata"]];
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: mom];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSXMLStoreType
configuration:nil
URL:url
options:nil
error:&error]){
// EDIT: if error opening persistent store, remove it and create a new one
if([[error domain] isEqualToString:#"NSCocoaErrorDomain"] && [error code] == 134100) {
NSLog(#"Core Data model was updated. Deleting old persistent store.");
[[NSFileManager defaultManager] removeItemAtURL:url error:nil];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSXMLStoreType
configuration:nil
URL:url
options:nil
error:&error]){
[[NSApplication sharedApplication] presentError:error];
[persistentStoreCoordinator release], persistentStoreCoordinator = nil;
return nil;
}
} else {
[[NSApplication sharedApplication] presentError:error];
[persistentStoreCoordinator release], persistentStoreCoordinator = nil;
return nil;
}
//
}
return persistentStoreCoordinator;
}
Figure out where your app stored the document and put it in the trash.
But as a extended comment you may wish to examine the possibilities around both explicit and implicit migration in NSPersistentStoreCoordinator and the options in.
- (NSPersistentStore *)addPersistentStoreWithType:(NSString *)storeType configuration:(NSString *)configuration URL:(NSURL *)storeURL options:(NSDictionary *)options error:(NSError **)error
Depending how different the versions are you can get it to happen automagically by passing NSMigratePersistentStoresAutomaticallyOption & NSInferMappingModelAutomaticallyOption
theres also
- (NSPersistentStore *)migratePersistentStore:(NSPersistentStore *)store toURL:(NSURL *)URL options:(NSDictionary *)options withType:(NSString *)storeType error:(NSError **)error
i need help!!!^^
I write in my attributes (name,prename) the two names of the person and save them. If i try to access the attrubutes in another view then they are nil. I don't understand why?!?
I did it this way. I get the profileContext with the method getProfile and i access the Attributes with the Dot-Notation, then i save it. My NSLog show me the right name and my fetch too.
ownProfile = [[MyProfile alloc] init];
profileContext = [ownProfile getProfile];
ownProfile = (MyProfile*)[NSEntityDescription insertNewObjectForEntityForName:#"MyProfile" inManagedObjectContext:profileContext];
ownProfile.Vorname = #"Max";
ownProfile.Nachname = #"Wilson";
NSLog(#"%#",ownProfile.Nachname);
if ([profileContext hasChanges]) {
NSLog(#"It has changes!");
[profileContext save:nil];
}
//Fetching
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"MyProfile" inManagedObjectContext:profileContext];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:entityDescription];
NSArray *array = [profileContext executeFetchRequest:request error:nil];
for (int i=0; i < [array count]; i++) {
MyProfile *object = [array objectAtIndex:i];
NSLog(#"Name: %#",object.Nachname);
}
if i try to access the attributes in another ViewController subclass they are nil. This is the code:
- (void)viewDidLoad {
[super viewDidLoad];
ownProfile = [[MyProfile alloc] init];
NSManagedObjectContext *profileContext = [ownProfile getProfile];
ownProfile = [NSEntityDescription insertNewObjectForEntityForName:#"MyProfile" inManagedObjectContext:profileContext];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"MyProfile" inManagedObjectContext:profileContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDescription];
[request setIncludesPropertyValues:NO]; //only fetch the managedObjectID
NSArray *array = [profileContext executeFetchRequest:request error:nil];
[request release];
MyProfile *object = [array objectAtIndex:[array count]-1];
NSLog(#"%#",object);
}
my getProfile method is in the NSManagedObjectClass and look like this:
-(NSManagedObjectContext*) getProfile {
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],
NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES],
NSInferMappingModelAutomaticallyOption, nil];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
NSLog(#"basePath = %#",basePath);
NSURL *storeUrl = [NSURL fileURLWithPath:[basePath stringByAppendingFormat:#"CoreData.sqlite"]];
NSPersistentStoreCoordinator *persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[NSManagedObjectModel mergedModelFromBundles:nil]];
NSLog(#"PersistentStore = %#",persistentStoreCoordinator);
NSError *error = nil;
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
NSLog(#"error loading persistent store..");
[[NSFileManager defaultManager] removeItemAtPath:storeUrl.path error:nil];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
NSManagedObjectContext *profile = [[NSManagedObjectContext alloc] init];
[profile setPersistentStoreCoordinator:persistentStoreCoordinator];
return profile;
}
Please help me!!!^^
Hey guys...I solved my problem!!! :)
My fault was that I add in the viewDidLoad-Method in the line
ownProfile = [NSEntityDescription insertNewObjectForEntityForName:#"MyProfile" inManagedObjectContext:profileContext];
another object in the persistentStore and i was always reading the new object where the attributes are nil...of course^^
I'm trying to expand my Core Data. So I added a new attribute to my entity and tried using the Automatic Lightweight Migration. But when I'm starting the programm the error Persistent store migration failed missing source managed object model pops up.
Anyone knows what goes wrong?
The relevant part of my AppDelegate.c (in fact I only added NSDictionary *options):
- (NSPersistentStoreCoordinator *) persistentStoreCoordinator {
if (persistentStoreCoordinator) return persistentStoreCoordinator;
NSManagedObjectModel *mom = [self managedObjectModel];
if (!mom) {
NSAssert(NO, #"Managed object model is nil");
NSLog(#"%#:%# No model to generate a store from", [self class], _cmd);
return nil;
}
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *applicationSupportDirectory = [self applicationSupportDirectory];
NSError *error = nil;
if ( ![fileManager fileExistsAtPath:applicationSupportDirectory isDirectory:NULL] ) {
if (![fileManager createDirectoryAtPath:applicationSupportDirectory withIntermediateDirectories:NO attributes:nil error:&error]) {
NSAssert(NO, ([NSString stringWithFormat:#"Failed to create App Support directory %# : %#", applicationSupportDirectory,error]));
NSLog(#"Error creating application support directory at %# : %#",applicationSupportDirectory,error);
return nil;
}
}
NSURL *url = [NSURL fileURLWithPath: [applicationSupportDirectory stringByAppendingPathComponent: #"stats.darx"]];
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: mom];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:url
options:options
error:&error]){
[[NSApplication sharedApplication] presentError:error];
[persistentStoreCoordinator release], persistentStoreCoordinator = nil;
return nil;
}
return persistentStoreCoordinator;
}
You need to use a versioned Managed Object Model, containing both versions of your model. The automatic migration still needs to see both the existing and new versions of your model in order to work out what the differences are, and how to handle them.
The error you quote suggests that your app bundle now contains only your new model (the one you want to use), and not the old one (the one you're trying to migrate from). Go back into your version control system and retrieve the old model, then set up a versioned model containing the old model as v1 and the new one as v2.