I run my program that creates Core Data content that is displayed in a NSOutlineView using NSTreeController. The second time I run my program I want to clean the content of my NSTreeController
and I run the method pasted below. The method either hangs for a long time (600 seconds) before it finishes or it crashes. If I have few entities (500-1000) in my NStreeController
it takes much less time compared to if I have a lot (200,000) entities to pass this method, if it passes at all. What I need to know is if there is a better way to clear/refresh/reset the content of my NStreeController
to clear my NSoutlineView
before I re-run my program and fill up the NStreeController
again. Specifically, I would like my NSOutlineView
to respond quickly to changes to the contents of my NSTreeController
, and I need the content of my Core Data driven NSTreeController
to be able to be reset.
-(void) cleanSDRDFileObjects
{
__weak __typeof__(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.outlineView collapseItem:nil collapseChildren:YES];
[weakSelf.coreDataController._coreDataHelper.context performBlockAndWait:^{
NSEntityDescription *entityDescription = [NSEntityDescription
entityForName:@"SDRDFileObject" inManagedObjectContext:weakSelf.coreDataController._coreDataHelper.context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDescription];
NSArray * result = [weakSelf.coreDataController._coreDataHelper.context executeFetchRequest:request error:nil];
for (id fileobject in result){
[weakSelf.coreDataController._coreDataHelper.context deleteObject:fileobject];
}
[weakSelf.coreDataController._coreDataHelper.context processPendingChanges];
NSLog(@"Finished deleting all objects");
}];
});
}
The managedobjectcontext (context
) is run as type NSMainQueueConcurrencyType
and the method is run on the main thread. Suggestions for improvements, or useful examples for the combination of reset/refreshing NSOutlineView + Core Data would be greatly appreciated. Thanks. Cheers, Trond
In response to @TomHarringtons question I took a picture of my Time Profiler. I really dont understand why it hangs on this method, however, after commenting this methods out (```processPendingChanges```), it still hangs and takes forever to finish (6 minutes). It seems the process gets stuck on the main thread and can
t continue.
When I rerun the application, with processPendingChanges
commented out its still hanging.
Update
I believe I solved this but I am slightly uncertain as to why this worked. It seems that my first method went into an indefinite loop that did not release its objects. The following simple solution worked:
__weak __typeof__(self) weakSelf = self;
dispatch_sync(dispatch_get_main_queue(), ^{
[weakSelf.coreDataController._coreDataHelper.context reset];
});
I was certain that to properly empty a managed object context I would have to delete each entity individually. The reset function seems pretty brute force and does it actually clean up memory and make sure everything is okay? If anyone wants to shed some light on this that would be appreciated.
Looking at this again, you fetched all objects of a type in performBlockAndWait
-- this blocks the main thread because you have mainQueueConcurrency and you used the andWait version of performBlock.
You then delete each object one-by-one. These objects are in a tree data structure with a outlineview attached (see the KVO messages in the stack trace). These objects have to-many relationships that need to be maintained by core data, hell, you could even have a cascading delete rule. (see propagateDelete and maintainInverseRelationship in the stack trace) In any event, you start requesting that both the data source and the view start doing a lot of work, on the main thread. You could try using a child MOC with privateQueueConcurrency if you wanted to iterate all objects in the background.
But, like the comments indicated:
NSManagedObjectContext's reset
most definitely frees up memory, and it's fine for what you want to do here: blow everything away.
It begs the question why you load the model from the store on disk in the first place, though.
If you want Core Data, but not persistence between the times you run the program, you can initialize the persistentStoreCoordinator with a store of NSInMemoryStoreType
rather than pointing it to a file URL.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With