Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS - CoreData fault causing null values

When I first populate a view I do this:

self.cats = [[DataManager sharedManager] getCatsFromCoreData]; //cats is an NSArray property (strong)
for (Cat* cat in self.cats)
    {
        CatThumbnailView *thumb = [CatThumbnailView catThumbnailView];
        thumb.cat = cat;

        UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(thumbnailTapped:)];
        [thumb addGestureRecognizer:tap];
        [thumb setText:[cat.name uppercaseString]];

        ...


        [self.someScrollview addSubview:thumb];
        yPos += thumb.frame.size.height + spacing;
    }

The DataManager's get method looks like this:

- (NSArray*)getCatsFromCoreData
{

    NSManagedObjectContext *context = [[CoreDataController sharedController] managedObjectContext];

    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:[NSEntityDescription entityForName:@"Cats" inManagedObjectContext:context]];
    [request setSortDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"order" ascending:YES]]];


    NSError *error = nil;
    NSArray *fetchedCats = [context executeFetchRequest:request error:&error];


    if (fetchedCats.count > 0) {
        return fetchedCats;
    }

    return nil;
}

That all works fine. The view is populated. The thumbnail tap method looks like this:

- (void)thumbnailTapped:(UITapGestureRecognizer*)tap
{

    CatThumbnailView* thumb = (CatThumbnailView*)tap.view;

    DLog(@"cat %@", thumb.cat);
    DLog(@"cat id: %@", thumb.cat.cat_id);

    //do stuff here with the cat data

}

The problem is that sometimes when I tap on a cat thumbnail, I get this:

cat <Cat: 0x7fa450> (entity: Cat; id: 0x7b71f0 <x-coredata://7C904BD2-16AA-486D-8D1B-C2D0ABCCB6D4/Cat/p1> ; data: <fault>)
cat id: (null)

Because the cat id is null, the app crashes when I try to do something with it.

So the cat id is never null when I first retrieve the cat objects from CoreData and lay out the view. It's when I later tap one of the thumbnails that the data has become a fault, so that when I access the cat_id property, it is null. The CatThumbnailView retains the Cat entity:

@property (nonatomic, strong) Cat* cat;

Why does this happen, and what do I do about it?

*note - this doesn't happen every time I tap a thumbnail. I'd say it happens 10-20% of the time. The other 80-90% of the time the data is not a fault. Why????

like image 327
soleil Avatar asked Sep 17 '13 19:09

soleil


2 Answers

I know this is a little old, but the most likely explanation is that your implementation of your Cat class looked something like this:

@implementation Cat
@synthesise cat_id = _cat_id;
...
@end

When it should have looked like this:

@implementation Cat
@dynamic cat_id;
...
@end

I just made this mistake myself, so sharing this in the hope that it saves the next person a bit of time!

like image 149
smee Avatar answered Sep 18 '22 23:09

smee


Core data will not return full object until there is a need to access the actual value of that object. Each of your returned objects will be a 'fault' until this point.

You can use [request setReturnsObjectsAsFaults:NO] on Fetch Request to forcefully get complete object, but this is not necessary in most of the cases.


In your case, i suspect manageObjectContext is some how reached to invalid state or not available at the time of fetching objects.

Instead of restricting manageObjectContext's scope to your method getCatsFromCoreData only, declare manageObjectContext at controller level so that it is available at the time of actual fetching of object.

P.S. Make sure manageObjectContext is available at the time of actual fetching of object.

Hope this will help you.

like image 27
Moin Ahmed Avatar answered Sep 19 '22 23:09

Moin Ahmed