Search code examples
iosobjective-csqlitecore-datansfetchrequest

Core Data Set Up, Saving Duplicates and Returning Empty Objects


ANSWERED Q2 by FIXING Q1, FEEL FREE TO EXPLAIN IF YOU KNOW WHY

Full disclosure, I dabble in Objective C so this could be painfully obvious but I could not find similar problems or more accurately answers to similar problems.

I'm writing a very simple app and I am learning about core data and I have a couple of issues

Q.1 Has been answered so here is Q.2

Q2. When fetching from Core Data I retrieve empty objects?

With the Data Controller being the same as the above question I call

- (NSMutableArray*) returnTimers
{
    [self initilizeDataLayer];

NSMutableArray *listOfTimers = [[NSMutableArray alloc]init];

NSFetchRequest *request = [[NSFetchRequest alloc]initWithEntityName:@"Timer"];

NSError *error = nil;

NSArray *listOfTimersRaw = [myDataController.managedObjectContext executeFetchRequest:request error:&error];


if (error != nil) {

        //Deal with failure
}
else {

    //Deal with success
    listOfTimers = [NSMutableArray arrayWithArray:listOfTimersRaw];

}

return listOfTimers;


}

This correctly retrieves 2 objects but they are empty?

Again this is experimentation so may be arse ways but I have to learn somehow.....Any help would be greatly appreciated.

BELOW HERE HAS BEEN ANSWERED THANKS

Q1. Saving Objects to Core Data creates a blank row in sqlite db - Why?

I have set up a DataController Object like in the Apple Docs

- (void)initializeCoreData
{
    NSURL *modelURL = [[NSBundle mainBundle]  URLForResource:@"WorkRestWork" withExtension:@"momd"];
    NSManagedObjectModel *mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    NSAssert(mom != nil, @"Error initializing Managed Object Model");

    NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
    NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    [moc setPersistentStoreCoordinator:psc];
    [self setManagedObjectContext:moc];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSURL *documentsURL = [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
    NSURL *storeURL = [documentsURL URLByAppendingPathComponent:@"WorkRestWork.sqlite"];

    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
    NSError *error = nil;
    NSPersistentStoreCoordinator *psc = [[self managedObjectContext] persistentStoreCoordinator];
    NSPersistentStore *store = [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:_options error:&error];
    NSAssert(store != nil, @"Error initializing PSC: %@\n%@", [error localizedDescription], [error userInfo]);
    });
}

Then I call this method

- (BOOL) addTimerWithName: (NSString*)timerName
{
    [self initilizeDataLayer];

 Timer *newTimer = [NSEntityDescription insertNewObjectForEntityForName:@"Timer" inManagedObjectContext:myDataController.managedObjectContext];

newTimer = [NSEntityDescription insertNewObjectForEntityForName:@"Timer" inManagedObjectContext:myDataController.managedObjectContext];

newTimer.name = timerName;

[myDataController.managedObjectContext insertObject:newTimer];

NSError *error = nil;
if ([myDataController.managedObjectContext save:&error] == NO) {
        NSAssert(NO, @"Error saving context: %@\n%@", [error localizedDescription], [error userInfo]);

    return NO;
}

    return YES;
}

And Finally

[cdh addTimerWithName:@"A TEST"];

When I check check the .sqlite file using Base there are 2 rows, one with "A TEST" as the Name and the other empty which is confusing me


Solution

  • Ad Q1. You are inserting two timers here. However you assign a name just to the second one. First one has no name cause you never set it. Here's your code with some comments:

    // Inserts first timer 
    Timer *newTimer = [NSEntityDescription insertNewObjectForEntityForName:@"Timer" inManagedObjectContext:myDataController.managedObjectContext];
    // Inserts second timer
    newTimer = [NSEntityDescription insertNewObjectForEntityForName:@"Timer" inManagedObjectContext:myDataController.managedObjectContext];  
    // Sets name of the second timer
    newTimer.name = timerName;