Core Data: Memory not released after manually faul

2019-06-04 08:42发布

问题:

I am using the following code to retrieve the maximum value of an attribute on Core Data

- (NSDate*)latestDateForLocalEntity:(NSString*)entityString
   key:(NSString*)key 
   inManagedObjectContext:(NSManagedObjectContext*)context {

   NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:entityString];
   NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:key ascending:YES];
   request.sortDescriptors = @[sortDescriptor];
   NSError *localError;
   NSArray *localResults = [context executeFetchRequest:request error:&localError];
   id result = localResults.lastObject;

   NSDate *latestLocalDate = [result valueForKey:key];
   NSLog(@"Latest local date for entity %@ (%@): %@",entityString,key,latestLocalDate);

   // fault newly created objects - don`t need to keep them in RAM:
   [localResults enumerateObjectsUsingBlock:^(NSManagedObject *managedObject, NSUInteger idx, BOOL *stop) {
      [context refreshObject:managedObject mergeChanges:NO];
   }];

   // even context reset does not help reducing RAM consumption:

  [context reset];
  localResults = nil;
  return latestLocalDate;

The code retrieves all entities, sorts them by value and takes the last object to get the maximum value. It then tries to (re)fault the values in order to release RAM: [context refreshObject:managedObject mergeChanges:NO].

However, memory seems not being released (roughly 400.000 non-objectobjects are kept in memory).

What is wrong with my code trying to refault the objects and resetting the managed object context? Why does it not release memory?

回答1:

If you are only interested in the maximum value of one attribute, I would suggest that you fetch only one object with

// Sort descending to that the first object is that with the maximum value.
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:key ascending:NO];
[request setSortDescriptors:@[sortDescriptor]];
[request setFetchLimit:1];

Then only one object is loaded into memory instead of all objects of that entity.

In addition, you can fetch only the attribute that you are interested in instead of the managed object:

[request setResultType:NSDictionaryResultType];
[request setPropertiesToFetch:@[key]];

Then the result is an array of dictionaries and no managed objects are loaded at all into the context. One caveat here is that the result reflects the current state in the persistent store, and does not take into account any pending changes, insertions, or deletions in the context.