Question

I have two NSManageObjects, Midwife and Patient. These both have the parent entity of User. The only difference is that a Midwife object has a many to many relationship to Patient and the Patient object has a many to many relationship to Midwife

This shows the NSManagedObjects and their relationships

When I get the active user it correctly returns the user and identifies if it is a Midwife or a Patient. You can see with the image below that it correctly retrieves the object I want with the patients relationship faulted. enter image description here

Using the code below I determine that the relationship is a fault then try to access a property to make core data fulfil the fault. I then add the object to a mutable array to be used late in a collection view.

[User activeUserSuccess:^(id user) {
    self.activeMidwife = (Midwife *)user;
    self.patients = [@[] mutableCopy];

    [[[_activeMidwife patients] allObjects] enumerateObjectsUsingBlock:^(Patient *patient, NSUInteger idx, BOOL *stop) {
        NSLog(@"Is fault : %i", [patient isFault]);
        [patient fullName];
        NSLog(@"Is fault : %i", [patient isFault]);

        [_patients addObject:patient];
    }];

} failure:^(NSError *error) {
    NSLog(@"Error : %@", [error description]);
}];

The first NSLog returns "Is fault : 1" and then once I call the fullName method (this simply places the forename and surname property together with a space) the object is then loaded and the second NSLog outputs "Is fault : 0" Whilst still in the enumerate block I print out the patient.mangaedObjectContext and here it returns a valid managedObjectContext it then adds it to the mutable array and does this fall all patents for the active midwife.

The problem is when I access the _patents array from within the - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath method the managedObjectContext is nil. My code is below.

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    MDCCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];

    Patient *patient = _patients[indexPath.row];
    NSLog(@"Is fault : %i", [patient isFault]);
    NSLog(@"Patitne name %@", patient.forename);
    NSLog(@"Is fault : %i", [patient isFault]);
    [[cell patientNameLabel] setText:[patient fullName]];

    return cell;
}

Within these two NSLogs they both output "Is fault : 1". When debuting I found that the patent object at this point the patent object has a nil managedObjectContext. Would anyone know why or accord this problem before.

My persistentStore is only init once and accessed via a sharedInstance.

Thanks for the help.

Was it helpful?

Solution

Quick answer to reflect comments. If the MOC goes out of scope, then it makes sense the entity instance pointers that you've retained have internal pointers to a MOC that's now nil.

Beyond that, I don't know what is supposed to happen with the usability or mutability of these NSManagedObjects that are now retained outside the scope of the MOC you got them from. So there's potentially a more informed answer about what you could or could not do with that array you've created.

OTHER TIPS

You might be better off refactoring your design to have the MDCDataStore perform all the fetches and just return Arrays of Patients per each MidWife.

I've got it working. I had to return the managed objects that were on the main context.

By adding the code below to get the objects on the mainContext this worked.

[fetchedObjects enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    id entity = [[[MDCDataStore sharedInstance] mainContext] objectWithID:[obj objectID]];
    [objectsOnMainContxt addObject:entity];
}];

Is there a better way to do this?

The entire function is as below

+ (void)entityName:(NSString *)entityName predicate:(NSPredicate *)predicate relationshipKeyPathsForPrefetching:(NSArray *)relationshipKeyPathsForPrefetching success:(void (^)(NSArray *fetchedObjects))success failure:(void (^)(NSError *error))failure
{
    NSManagedObjectContext* context = [[[MDCDataStore sharedInstance] store] newPrivateContext];
    NSEntityDescription *entityDescription = [NSEntityDescription entityForName:entityName inManagedObjectContext:context];

    [context performBlock:^{
        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
        [fetchRequest setEntity:entityDescription];
        [fetchRequest setPredicate:predicate];
        [fetchRequest setRelationshipKeyPathsForPrefetching:relationshipKeyPathsForPrefetching];
        NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:nil];

        NSMutableArray *objectsOnMainContxt = [@[] mutableCopy];

        if([fetchedObjects count] > 0)
        {
            [fetchedObjects enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
                id entity = [[[MDCDataStore sharedInstance] mainContext] objectWithID:[obj objectID]];
                [objectsOnMainContxt addObject:entity];
            }];

            if(success)
            {
                success(objectsOnMainContxt);
            }
        }
        else if(failure)
        {
            NSError *error = [NSError errorWithCode:CoreDataErrorCodeEntityNotFound
                                         reason: @"There were no managed objects that matched the predicate and that existed in the context."
                                    description:[NSString stringWithFormat:@"No managed object matched the predicate '%@'.", [predicate predicateFormat]]
                                     suggestion:@"Ensure you are passing in the correct params into the predicate."];

            failure(error);
        }
    }];

}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top