开发者

"Dangling reference to an invalid object" error in Core Data with seemingly valid objects

I'm having a really confounding problem using Core Data. In my Core Data store, for an existing Core Data object, I'm checking whether a relationship exists, and if not, I create the object like so (this is a method on AFFingerprintGeneratorOperation):

NSManagedObjectContext *newContext = [[NSManagedObjectContext alloc] init];
[newContext setMergePolicy:NSOverwriteMergePolicy];
NSPersistentStoreCoordinator *sharedStoreCoordinator = [[AFMainController sharedInstance] persistentStoreCoordinator];
[newContext setPersistentStoreCoordinator:sharedStoreCoordinator];
[self setManagedObjectContext:newContext];  // retaining 开发者_Go百科property
[newContext release];

NSEntityDescription *fetchedTagSetEntity = [NSEntityDescription entityForName:@"FetchedTagSet"
                                                       inManagedObjectContext:newContext
                                            ];

AFTrack *retrievedTrack = (AFTrack *)[newContext objectWithID:[self trackObjectID]];
[self setTrack:retrievedTrack];

if (! retrievedTrack.fetchedTagSet) {
    AFFetchedTagSet *newFetchedTagSet = [[AFFetchedTagSet alloc] initWithEntity:fetchedTagSetEntity
                                                 insertIntoManagedObjectContext:newContext];

    [[retrievedTrack storedTrack] setFetchedTagSet:newFetchedTagSet];
    [newFetchedTagSet setStoredTrack:[retrievedTrack storedTrack]];
}

AFTrack, AFFetchedTagSet, and AFStoredTrack are all Core Data objects. AFFetchedTagSet and AFStoredTrack are in an on-disk Core Data store, while AFTrack is in a separate in-memory Core Data store.

Note that since the AFStoredTrack object is in a separate store, I need to fetch it like so (this is a method on AFTrack):

NSManagedObjectContext *objectContext = [self managedObjectContext];
NSPersistentStoreCoordinator *coordinator = [objectContext persistentStoreCoordinator];
NSString *URIString = [self storedTrackObjectIDString];

AFStoredTrack *theStoredTrack = nil;
if (URIString) {
    NSURL *objectURL = [NSURL URLWithString:URIString];
    NSManagedObjectID *storedTrackObjectID = [coordinator managedObjectIDForURIRepresentation:objectURL];
    theStoredTrack = (AFStoredTrack *)[objectContext objectWithID:storedTrackObjectID];
}

return theStoredTrack;

Since this is a method on AFTrack, it simply retrieves the AFTrack's own managed object context, so the code in the first excerpt should always use the exact same managed object context for all operations.

However, in the first excerpt, after calling setFetchedTagSet: with the new object, and attempting to save the Core Data store, I get this error:

"Dangling reference to an invalid object." = "<null>";
NSAffectedObjectsErrorKey =     (
    "<AFStoredTrack: 0x11550eef0> (entity: StoredTrack; id: 0x101eb57d0 <x-coredata:///StoredTrack/tF7F5568E-2959-4786-B73D-B7AC6586F5B9121> ; data: {\n    fetchedTagSet = \"0x11c956b60 <x-coredata:///FetchedTagSet/tF7F5568E-2959-4786-B73D-B7AC6586F5B9124>\";\n    fingerprint = \"ASPtPiNHPC7fGSYXTxtfFboMCg7BCxYQ+gZRCL4FWQdzBD8HPw\";\n    persistentID = nil;\n    status = 3;\n    updateAlbumName = nil;\n    updateArtistName = nil;\n    updateArtwork = nil;\n    updateGenre = nil;\n    updateLyrics = nil;\n    updateReleaseYear = nil;\n    updateTrackName = nil;\n})"
);
NSLocalizedDescription = "storedTrack is not valid.";
NSValidationErrorKey = storedTrack;
NSValidationErrorObject = "<AFFetchedTagSet: 0x11c956ac0> (entity: FetchedTagSet; id: 0x11c956b60 <x-coredata:///FetchedTagSet/tF7F5568E-2959-4786-B73D-B7AC6586F5B9124> ; data: {\n    ampliFindPUID = nil;\n    fingerprint = nil;\n    matchAlbum = nil;\n    matchLyrics = nil;\n    matchTrackName = nil;\n    matchTrackNumber = 0;\n    storedTrack = \"0x101eb57d0 <x-coredata:///StoredTrack/tF7F5568E-2959-4786-B73D-B7AC6586F5B9121>\";\n})";
NSValidationErrorValue = "<AFStoredTrack: 0x11550eef0> (entity: StoredTrack; id: 0x101eb57d0 <x-coredata:///StoredTrack/tF7F5568E-2959-4786-B73D-B7AC6586F5B9121> ; data: {\n    fetchedTagSet = \"0x11c956b60 <x-coredata:///FetchedTagSet/tF7F5568E-2959-4786-B73D-B7AC6586F5B9124>\";\n    fingerprint = \"ASPtPiNHPC7fGSYXTxtfFboMCg7BCxYQ+gZRCL4FWQdzBD8HPw\";\n    persistentID = nil;\n    status = 3;\n    updateAlbumName = nil;\n    updateArtistName = nil;\n    updateArtwork = nil;\n    updateGenre = nil;\n    updateLyrics = nil;\n    updateReleaseYear = nil;\n    updateTrackName = nil;\n})";

But both the AFFetchedTagSet and AFStoredTrack objects seem to be valid, as their ids match up, and the object context for these objects still exists and is retained by the AFFingerprintGeneratorOperation object.

I've seen this CoreData: "Dangling reference to an invalid object." error and this http://lists.apple.com/archives/cocoa-dev/2009/Nov/msg00190.html , but neither link seems to help. The former seems to say that a relationship is bad (which I don't think it is), and the latter says to avoid changing relationships in awakeFromFetch, which as far as I can tell I'm not doing.

Any help?


The error code that Core Data was throwing was actually quite correct in this instance, but it was hard to figure out what was going on.

The "fetchedTagSet" property on AFTrack objects was simply a convenience read-only property for the "fetchedTagSet" property on AFStoredTrack, meaning that in order to retrieve the AFFetchedTagSet class, I had to retrieve the AFStoredTrack object first.

The method on AFTrack that was fetching the AFStoredTrack method was using the objectRegisteredForID: method. This doesn't fetch objects if they aren't registered with the managed object context that you're calling the objectRegisteredForID: method on. So, I was retrieving non-existent AFStoredTrack faults, and setting properties on them.

(Note: "aren't registered with the managed object context" does not mean that they don't exist in the Core Data store. It simply means that that specific managed object context does not know about that object yet, because you haven't inserted it or fetched it within that context.)

For some reason, objectRegisteredForID: was returning a blank AFStoredTrack, rather than nil as the documentation states. The effect was that I thought I had a valid AFStoredTrack object, but in reality it was just a placeholder with all the values being nil. Trying to save the object made the context realize that the AFStoredTrack was not valid, producing the error message.

The fix was to change the method on AFTrack (the one that retrieved the AFStoredTrack objects) to use objectWithID: rather than objectRegisteredForID: . As the documentation states, objectWithID: will fetch an object if the context doesn't know about it yet. That returned a valid object, and then everything went fine after that.


My problem was solved using this code:

[[CustomManagedObject managedObjectContext] performBlockAndWait:^{
        NSError *error;
        if (![[CustomManagedObject managedObjectContext] save:&error])
        {
            NSLog(@"Error in Saving: %@", [error.userInfo description]);
        }
    }];


Since you're dealing with objects split across two different stores here, and relationships are not allow to span across different stores, you might need to make sure that the AFFetchedTagSet you're creating is assigned to the same persistent store as the AFStoredTrack object you're associating it with. I'm not sure which store Core Data defaults to when creating a new object, but I could see Core Data throwing a fit when you try to save a context that has a relationship set up that spans across the two stores, so setting the store explicitly surely couldn't hurt. You can do this by calling -[NSManagedObjectContext assignObject:toPersistentStore:] after creating the fetched tag set. Not 100% sure that's the problem, but that's what I'd try first.

As a side note, if you have inverse relationships set up in your Core Data model between AFFetchTagSet and AFStoredTrack, then only one of the two calls from -setFetchedTagSet: and -setStoredTrack: should be necessary, and Core Data should take care of the other one automagically.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜