Completion block/callback on FetchRequest completion - iphone

I have a FetchRequest in my model class named ContentManager. It fetches quite a lot of data, so the screen is blank until it's completion. In the ViewController that displays the fetched results, I would like to show a loading indicator, so I would like to get a callback when the FetchRequest has completed and pass that to the ViewController to stop the loading indicator. Is this possible?
Here is the FetchRequest from the ContentManager class:
- (NSArray*)recipesForMagazine
{
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Recipe" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSString* path = [[NSBundle mainBundle] pathForResource:#"magazine_recipe_guids" ofType:#"plist"];
NSArray* recipeGuids = [NSArray arrayWithContentsOfFile:path];
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"guid IN %#",recipeGuids];
[request setPredicate:predicate];
NSSortDescriptor* sort = [[NSSortDescriptor alloc] initWithKey:#"title" ascending:YES selector:#selector(localizedCaseInsensitiveCompare:)];
[request setSortDescriptors:[NSArray arrayWithObject:sort]];
[sort release];
NSError* error = nil;
NSArray* fetchResults = [managedObjectContext executeFetchRequest:request error:&error];
[request release];
return fetchResults;
}
Here I set it up in the ViewController
self.magazineRecipes = [[ContentManager defaultManager] recipesForMagazine];
I want to set up the fetchrequest method like this:
- (NSArray*)recipesForMagazine:(void (^)(BOOL success))block or something, so in the viewcontroller I can call it like this
self.magazineRecipes = [[CTContentManager defaultManager] recipesForMagazine:^(BOOL success) {
if (success) {
//stop activity indicator view
}
}];
I don't know if I'm at all in the right way of thinking, thanks for your help in advance!

I would make the viewController a delegate of the ContentManager class. So in the ContentManager.h I would do something like:
#protocol ContentManagerDelegate()
-(void) didFetchResults:(NSArray *) results;
-(void) didResultsFail: (NSError *) error;
#end
#interface ContentManager : <SuperClass Name>
-(id) initWithDelegate: (id<ContentManagerDelegate>) delegate;
#property (nonatomic, strong) id<ContentManagerDelegate> delegate;
#end
and in the implementation:
-(id) initWithDelegate: (id<ContentManagerDelegate>) delegate
{
self = [super init];
if(self)
{
_delegate = delegate;
}
return self;
}
and in your recipesForMagazine method you can use the delegate [_delegate didFetchResults: fetchResults], you can implement a method to pass errors to the delegate if you want as well. In your ViewController.h do #interface ViewController.h : UIViewController <ContentManagerDelegate> and in the implementation you should be able to implement the didFetchResults: method that will give you the results and in that method you can stop the activity indicator from animating.

Related

Core data sort data by two Descriptor

I have used core data in my ios app. Now i have one table in which there are two columns .
Category
Order (In which there are NSNumber 1, 2 ,5)
I want to fetch data so It will first sort alphabetically by Category name and than by Order Number.
I have used below code :
NSEntityDescription *entity_Maintness = [NSEntityDescription
entityForName:#"Maintness" inManagedObjectContext:__managedObjectContext];
[fetchRequest_Maintness setEntity:entity_Maintness];
NSSortDescriptor *sortDescriptor1 = [[NSSortDescriptor alloc] initWithKey:#"type" ascending:YES];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"serialNumber" ascending:NO];
NSArray *sortDescriptors12 = [[NSArray alloc] initWithObjects:sortDescriptor1, sortDescriptor, nil];
[fetchRequest_Maintness setSortDescriptors:sortDescriptors12];
But the data are sorted only by Category not by Serial Number.
Thanks for Help.
The code above looks ok. Maybe there is an issue elsewhere in your code? Here is some code I quickly generated for you that may serve as starting point??
#import "MainViewController.h"
#import "Maintness.h"
#interface MainViewController ()
#property (weak, nonatomic) IBOutlet UITextField *type;
#property (weak, nonatomic) IBOutlet UITextField *serialNumber;
#property (strong, nonatomic) NSManagedObjectContext *context;
- (IBAction)addButtonPressed:(id)sender;
- (IBAction)retrieveButtonPressed:(id)sender;
#end
#implementation MainViewController
#pragma mark - lazy instantiation
- (NSManagedObjectContext *)context{
if (!_context){
id appDelegate = (id)[[UIApplication sharedApplication] delegate];
_context = [appDelegate managedObjectContext];
}
return _context;
}
#pragma mark - core data interactions
- (IBAction)addButtonPressed:(id)sender {
NSError *error = nil;
Maintness *newMaintness = nil;
newMaintness = [NSEntityDescription insertNewObjectForEntityForName:#"Maintness" inManagedObjectContext:self.context];
newMaintness.type = self.type.text;
newMaintness.serialNumber = self.serialNumber.text;
if (![self.context save:&error]) {
NSLog(#"Oh no - error: %#", [error localizedDescription]);
} else {
NSLog(#"It appears the details were added ok");
}
}
- (IBAction)retrieveButtonPressed:(id)sender {
NSError *error = nil;
// Set up fetch
NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
// Set up entity
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Maintness" inManagedObjectContext:self.context];
[fetch setEntity:entity];
// Set up sorting
// - sorts in order of array
NSSortDescriptor *primarySortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"type" ascending:YES];
NSSortDescriptor *secondarySortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"serialNumber" ascending:NO];
NSArray *sortDescriptors = #[primarySortDescriptor, secondarySortDescriptor];
[fetch setSortDescriptors:sortDescriptors];
NSArray *results = [self.context executeFetchRequest:fetch error:&error];
for (Maintness *result in results) {
NSLog(#"type: %# serial number: %#", result.type, result.serialNumber);
}
}
#end

Why is my managedObjectContext coming back nill?

I'm trying to use CLLocation Manager to get someone's location whenever they move and store the lat, lng, and timestamp into core data, then display that in a table view tab. However, the output in the console always indicates that managedObjectContext is nill by throwing this log coredataproject[12478:11903] After managedObjectContext: <NSManagedObjectContext: 0x7248230>
Here's the relevant code in my AppDelgate implementation file
#import "AppDelegate.h"
#import "RootViewController.h"
#import "FirstViewController.h"
#implementation AppDelegate
#synthesize window;
#synthesize navigationController;
#pragma mark -
#pragma mark Application lifecycle
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Configure and show the window.
RootViewController *rootViewController = [[RootViewController alloc] initWithStyle:UITableViewStylePlain];
NSManagedObjectContext *context = [self managedObjectContext];
if (!context) {
NSLog(#"Could not create context for self");
}
rootViewController.managedObjectContext = context;
UINavigationController *aNavigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
self.navigationController = aNavigationController;
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];
}
/**
applicationWillTerminate: saves changes in the application's managed object context before the application terminates.
*/
- (void)applicationWillTerminate:(UIApplication *)application {
NSError *error;
if (managedObjectContext != nil) {
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
// Handle the error.
}
}
}
Here is the FirstViewController.M code, where I'm getting the location and storing it in the core data 'Event' entity
- (void)viewDidLoad
{
locationManager =[[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.distanceFilter = kCLDistanceFilterNone;
[locationManager startUpdatingLocation];
-(void) locationmanager: (CLLocationManager *) manager
didUpdateToLocation: (CLLocation *) newLocation
fromLocation: (CLLocation *) oldLocation
{
CLLocation *location = [locationManager location];
if (!location) {
return;
}
/*
Create a new instance of the Event entity.
*/
RootViewController *rootviewcontroller = [RootViewController alloc];
Event *event = (Event *)[NSEntityDescription insertNewObjectForEntityForName:#"Event" inManagedObjectContext:rootviewcontroller.managedObjectContext];
// Configure the new event with information from the location.
CLLocationCoordinate2D coordinate = [location coordinate];
[event setLatitude:[NSNumber numberWithDouble:coordinate.latitude]];
[event setLongitude:[NSNumber numberWithDouble:coordinate.longitude]];
// Should be the location's timestamp, but this will be constant for simulator.
// [event setCreationDate:[location timestamp]];
[event setTimeStamp:[NSDate date]];
// Commit the change.
NSError *error;
if (![rootviewcontroller.managedObjectContext save:&error]) {
NSLog(#"Save Error");
}
//RootViewController *rootviewcontroller = [RootViewController alloc];
[rootviewcontroller.eventsArray insertObject:event atIndex:0];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[rootviewcontroller.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[rootviewcontroller.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
And finally here is the RootViewController file where I'm trying to fetch and display what's in the core data. It's when I click this tab that the console tells me that managedObjectConsole is nill
- (void)viewDidLoad {
[super viewDidLoad];
if (managedObjectContext == nil)
{
managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
NSLog(#"After managedObjectContext: %#", managedObjectContext);
}
// Set the title.
self.title = #"Locations";
/*
Fetch existing events.
Create a fetch request; find the Event entity and assign it to the request; add a sort descriptor; then execute the fetch.
*/
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Event" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
// Order the events by time stamp, most recent first.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"timeStamp" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
// Execute the fetch -- create a mutable copy of the result.
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResults == nil) {
NSLog(#"Mutable Fetch Results equals nill");
}
// Set self's events array to the mutable array, then clean up.
[self setEventsArray:mutableFetchResults];
}
I'm also doing some more stuff with organizing the table data once it's there, but I don't think that's where the problem is.
I'm unsure as to why nothing would be in managedObjectContext, as it should have the location data from the location manager. I'm not too familiar with Core data, so I'm probably just doing something simple wrong, but any insight would be appreciated!
Your mistake is in the didUpdateToLocation method. There you create a new instance of RootViewController. You just need to save the newLocation to CoreData and need the MOC for that (not the RootViewController). So you need to find a way to pass the MOC to the FirstViewController. You can do this similar like you did in the AppDelegate or like this:
managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
Why do you reset the MOC of RootViewController in viewDidLoad? You already passed it in applicationDidFinishLaunching!
I'd recommend to use a NSFetchedResultsController for the table view. It automatically detects changes of the data and reloads the table if needed, just implement the delegate correctly. Here is a helpful tutorial on this: http://www.raywenderlich.com/999/core-data-tutorial-how-to-use-nsfetchedresultscontroller

Core Data Memory Leaks

I began testing my app in Instruments to clean up any memory leaks. I've been able to clear up all the memory leaks except those related to Core Data. Instruments always points me to this section of code:
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResults == nil) {
// Handle the error
}
I declare the managedObjectContext in my header file with the following code:
#interface UpperBody : UITableViewController <UITableViewDelegate, UITableViewDataSource> {
IBOutlet UITableView *upperTable;
NSMutableArray *exercises;
NSManagedObjectContext *managedObjectContext;
}
#property (nonatomic, retain) NSMutableArray *exercises;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
I release the managedObjectContext in the (void)dealloc section. Here is the full section of code using the managedObjectContext:
- (void)loadExercises {
if (managedObjectContext == nil) {
managedObjectContext = [(iFitAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
}
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Exercises" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"category == 1"];
[request setPredicate:predicate];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"exerciseName" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptor release];
[sortDescriptors release];
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResults == nil) {
// Handle the error
}
[self setExercises:mutableFetchResults];
// [exercises addObject:#"Add Exercise"];
NSLog(#"Count of exercises %i", exercises.count);
[mutableFetchResults release];
[request release];
[self.tableView reloadData];
}
Any advise on what might be causing the leaks would be greatly appreciated! Thank you in advance!
kThere was probably a leak in the code I had above. I got around declaring an NSManagedObjectContext by just using a pointer to one whenever needed. Here is a sample of the code:
iFitAppDelegate *appDelegate = (iFitAppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *managedObjectContext = appDelegate.managedObjectContext;
This fixed my leak, so it must have had to do with how I was allocated and releasing the NSManagedObjectContext. Thank you for the pointers, #albertamg!

NSFetchedResultsController objectAtIndexPath crash (EXC_BAD_ACCESS)

I have a huge problem with NSFetchedResultsCOntroller. I'm using fetchedResultsContrioller and I have interface with 3 tabs. They use Core Data too. But I have a problem with only ONE of them.
Faktura *faktura = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = faktura.NumerFV; // THE CRASH IS HERE
int productsCount = [faktura.Produkty count]; // OR HERE
NSString *kontrahentName = [faktura.Kontrahent valueForKey:#"NazwaKrotka"]; // OR HERE
cell.detailTextLabel.text = [NSString stringWithFormat:#"nabywca: %#, produktów: %d",kontrahentName, productsCount];
cell.imageView.image = [UIImage imageNamed:#"faktura_cell_image.png"];
cell.hidesImageWhileEditing = YES;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
Faktura is my NSManagedObject subclass.
NSZombie says:
-[CFDictionary retain]: message sent to deallocated instance 0x5d619d0
My fetchedResultsController implementation:
- (NSFetchedResultsController *)fetchedResultsController {
if (__fetchedResultsController != nil) return __fetchedResultsController;
// Setup the table
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Faktura" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
// Setup the sort descriptors
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"DataWystawienia" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// Create the fetched results controller
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error]) { // THE CRASH IS HERE UNLESS I INIT NSFetchedResultsController WITH cacheName:nil. (IF IT'LL BE cacheName:#"Root" IT CRASHES.)
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Błąd Krytyczny" message:#"Wystąpił nieznany błąd przy zmienianiu zawartości w bazie danych. Dla dobra twoich danych prosimy niezwłocznie wyjść z aplikacji i spróbować ponownie." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[alert release];
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return __fetchedResultsController;
}
Faktura.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface NSArrayToDataTransformer : NSValueTransformer #end
#interface NSDictionaryToDataTransformer : NSValueTransformer #end
#interface Faktura : NSManagedObject
#property (nonatomic, retain) NSDate * DataZaplaty;
#property (nonatomic, retain) NSString * NumerFV;
#property (nonatomic, retain) NSDate * DataWystawienia;
#property (nonatomic, retain) NSDate * DataSprzedazy;
#property (nonatomic, retain) id Produkty;
#property (nonatomic, retain) id Kontrahent;
#end
Faktura.m
#import "Faktura.h"
#implementation Faktura
#dynamic DataZaplaty;
#dynamic NumerFV;
#dynamic DataWystawienia;
#dynamic DataSprzedazy;
#dynamic Produkty;
#dynamic Kontrahent;
+ (void)initialize {
if (self == [Faktura class] ) {
NSArrayToDataTransformer *arrayTransformer = [[NSArrayToDataTransformer alloc] init];
[NSValueTransformer setValueTransformer:arrayTransformer forName:#"NSArrayToDataTransformer"];
NSDictionaryToDataTransformer *dictTransformer = [[NSDictionaryToDataTransformer alloc] init];
[NSValueTransformer setValueTransformer:dictTransformer forName:#"NSDictionaryToDataTransformer"];
}
}
#end
#implementation NSArrayToDataTransformer
+ (BOOL)allowsReverseTransformation {
return YES;
}
+ (Class)transformedValueClass {
return [NSData class];
}
- (id)transformedValue:(id)value {
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:value];
return data;
}
- (id)reverseTransformedValue:(id)value {
NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithData:value];
return [array autorelease];
}
#end
#implementation NSDictionaryToDataTransformer
+ (BOOL)allowsReverseTransformation {
return YES;
}
+ (Class)transformedValueClass {
return [NSData class];
}
- (id)transformedValue:(id)value {
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:value];
return data;
}
- (id)reverseTransformedValue:(id)value {
NSDictionary *dict = [NSKeyedUnarchiver unarchiveObjectWithData:value];
return [dict autorelease];
}
#end
My Faktura object insertion code
- (void)fakturaCreator:(FakturaCreator *)form didEndWithValues:(NSDictionary *)values {
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity];
Faktura *newFaktura = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
[newFaktura setNumerFV:[values valueForKey:#"id"]];
[newFaktura setDataWystawienia:[values valueForKey:#"creationDate"]];
[newFaktura setDataSprzedazy:[values valueForKey:#"sellDate"]];
[newFaktura setDataZaplaty:[values valueForKey:#"paymentDate"]];
[newFaktura setKontrahent:[values valueForKey:#"kontrahent"]];
[newFaktura setProdukty:[values valueForKey:#"produkty"]];
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
[self.emptySectionView setHidden:YES];
}
FakturaCreator is my UIViewController where user create an invoice. values array contains dictionary of values: my invoice number (NSString), various dates (NSDate), client (NSDictionary) and products (NSArray).
Please help me!
If you want some additional code, i'll put it here.
EDIT: It is definetly objectAtIndexPath: fault. When I comment all the cell setup code (it will display empty cell) and then try to remove the cell, app crashes on line which contains objectatIndexPath:.
EDIT #2: Anybody? Please, help me... :(
I think I see the problem. In your NSArrayToDataTransformer, you have this:
- (id)reverseTransformedValue:(id)value {
NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithData:value];
return [array autorelease];
}
Since unarchiveObjectWithData: does not begin with "alloc", "new", "copy", or "mutableCopy", you do not own the object and therefore may not autorelease it. You have the same problem in your NSDictionaryToDataTransformer.
Your inclusion of the value transformers into the class and the using +initialize is non-standard. Although +initialize should work, it is recommended in the Core Data docs not use any kind of initialization methods at all but to rely on awakeFromFetch for initialization.
I would check your tableview methods such as numberOfRowsInSection: to ensure you are getting the right indexes back from the tableview. If the rows in the tableview and the count of the fetchedObjects array come out of sync, you can get this kind of crash.

Can't Release NSFetchedResultsController in dealloc

I have two UITableViewControllers with a fairly simple ui flow. One UITableViewController loads another UITableViewController when you select an item in the first UITableViewController.
(UITableViewController) List of Stories -> Select a Story -> (UITableViewController) List of Sentences
In the second UITableViewController (MakeSentenceDetailViewController) I can't release my NSFetchedResultsController without causing an error (shown with Zombies set to on):
-[NSFetchRequest release]: message sent to deallocated instance 0x5b370f0
The retain count of the NSFetchedResultsController stays at 1 but when I try to release it in dealloc I get a crash.
The code, especially in regards to the NSFetchedResultsController is the same in both tableviews, but in the MakeSentenceDetailViewController I can't release this NSFetchedResults Controller with a crash - giving me a leak.
How can I safely release my NSFetchedResultsController? Why does it work fine in the parent (first) tableviewcontroller - but not in the second?
I can provide code for the first UITableViewController but in regards to NSFetchedResultsController it's declared and used in much the same way.
MakeSentenceTableViewController.h:
#interface MakeSentenceTableViewController : UITableViewController {
NSManagedObjectContext *managedObjectContext;
NSFetchedResultsController *fetchedResultsController;
}
#property (nonatomic, retain) Story *story;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#end
MakeSentenceTableViewController.m (relevant code with NSFetchedResultsController):
- (void)viewDidLoad {
[super viewDidLoad];
if (managedObjectContext == nil)
{
managedObjectContext = [(MyAppAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
NSLog(#"After managedObjectContext: %#", managedObjectContext);
}
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Sentence" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
//sorting stuff:
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"order" ascending: YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects: sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
//[request setFetchBatchSize:FETCH_BATCH_SIZE];
[sortDescriptors release];
[sortDescriptor release];
fetchedResultsController = [[NSFetchedResultsController alloc]
initWithFetchRequest:request managedObjectContext:managedObjectContext
sectionNameKeyPath:nil cacheName:nil];
[request release];
NSError *error;
[fetchedResultsController performFetch:&error];
NSLog(#"FetchedResultsController: %#", fetchedResultsController);
NSLog(#"fetchedResultsController RetainCount at viewDidLoad: %d", [fetchedResultsController retainCount]);
}
- (void)dealloc {
//Gotta figure out why I can't release this:
[fetchedResultsController release]; //Crash! Burn!
NSLog(#"fetchedResultsController RetainCount at dealloc: %d", [fetchedResultsController retainCount]);
[managedObjectContext release];
[super dealloc];
}
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
// ...snip...
[request release];
You're releasing an object that you've relinquished ownership of (with -autorelease). You don't get an error at the point of the other release because the NSFetchedResultsController is also retaining the fetch request; thus the controller is the one actually causing the crash when it releases the last reference to the fetch request.
You are over-releasing the NSFetchRequest
You autorelease it here:
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
then release it again later:
[request release];
then later when you release the fetchedResultsController, it tries to release that same request again.