iOS - CoreData fault causing null values
Asked Answered
A

2

6

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????

Approximate answered 17/9, 2013 at 19:48 Comment(6)
A Core Date "fault" is just a placeholder object, and accessing a property "fires the fault" which means that the actual content is fetched from the underlying store. - So a "fault" is not an indicator for an error, and does not "cause null values".Chingchinghai
Thanks, but that doesn't really shed any light on the issue. When the app works properly, instead logging entity as a fault, it logs the actual entity with all it's proper values, and of course the cat id is valid in this case.Approximate
I just wanted to explain that your statement "the data has become a fault, so that when I access the cat_id property, it is null" is not correct. Nothing more.Chingchinghai
does [[CoreDataController sharedController] managedObjectContext] return a disposable context, or is this context being held strongly by the manager? was this context reset at any point in time?Aubrette
When/where are you putting cat data into core data? Does this ever change or is it a one time population of data?Neckwear
I'm experiencing the same issues, very few crashes after navigating a lot inside the app. Have you managed to solve this problem?Semiconductor
T
5

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!

Terr answered 16/2, 2014 at 21:52 Comment(3)
Thank you very much! This had me stumped why only one property was coming back nil and it was not resolving the fault even though I'd saved the context. I'd moved a transient property into the model without changing it to @dynamic. Doh.Demakis
lol, I had passed 3 days with this problem. Can anyone explain why this happen? whats the diference between @synthesise and @dynamic?Respect
Sweet! I just spent a few hours of troubleshooting before I found your response.Quadrennial
T
2

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.

Traverse answered 1/11, 2013 at 14:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.