Accessing data attribute of NSManagedObject gives

2019-08-31 02:07发布

问题:

I think I might be accessing this wrong, perhaps somebody could point me in the right direction.

I have a Entry entity, which has a one-to-many relationship with the Media entity. The Media entity contains a data attribute called originalImage.

The first 50 Entry entities that this iterates through do not have any media items in the set. After that, it slows down as it accesses the originalImage attribute and eventually runs out of memory and quits to the home screen, without any message other than a previous memory warning in NSLog. Running this through Instruments also shows it running out of memory at this point. Here's my code:

NSFetchRequest *oldFetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *oldEntryEntity = [NSEntityDescription entityForName:@"Entry"
                                                          inManagedObjectContext:oldMOC];
[oldFetchRequest setEntity:oldEntryEntity];
[oldFetchRequest setFetchBatchSize:10];
NSArray *entrys = [oldMOC executeFetchRequest:oldFetchRequest error:nil];

for (NSInteger index = 0; index < entrys.count; ++index) {

    Entry *entry = [entrys objectAtIndex:index];

    NSOrderedSet *oldMediaSet = [entry valueForKey:@"media"];

    for (Media *media in oldMediaSet) {

        @autorelease {

            [media valueForKey:@"originalImage"];    

        }

    }

}

Removing that originalImage line means it doesn't crash, which is what makes me believe it's related to that being accessed. Perhaps the way I get the orderedSet means these items stay in memory?

回答1:

Core Data is fulfilling the faults for the properties you are accessing, until it has filled up its available memory. You are trying to defend against this with @autorelease but that's not sufficient because you are not getting an autoreleased instance but rather another object in the object graph. Without knowing what you're trying to do it's hard to say how to resolve the issue. You're synchronously iterating in a loop until running out of memory so no memory warning is going to interrupt this process.



回答2:

So if you have a loop trying to move data from one entity to a new one in a different MOC, then what you should be doing is getting the old entity, assign the data to the new entity (don't copy it, will make your problem even worse), then fault the old object and the new object using 'refreshObject:mergeChanges:'. I believe this will work but have not myself tried it (assuming SQLite stores).

There are other suggestions in the Core Data Programming Guide 'Reducing Memory Overhead' (pg 148 of the pdf).