akashivskyy
akashivskyy

Reputation: 45170

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... :(

Upvotes: 1

Views: 1946

Answers (2)

Anomie
Anomie

Reputation: 94794

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.

Upvotes: 2

TechZen
TechZen

Reputation: 64428

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.

Upvotes: 1

Related Questions