views:

3608

answers:

2

I have a model where I have a Person entity and a Picture entity. In my Picture entity I have a property that is a relationship to a Person.

I would like to have an example about how to add a Picture to a Person because what I did doesn't work.

-(BOOL)savePicture:(NSString *)urlPicture:(Person *)person{
SettingsSingleton *userSettings = [SettingsSingleton sharedManager]; 
NSManagedObjectContext *managedObjectContext = [userSettings managedObjectContext]; 
NSEntityDescription *myContentEntity = [NSEntityDescription entityForName:@"Pictures" inManagedObjectContext:managedObjectContext];
NSManagedObject *contentToSave = [[NSManagedObject alloc] initWithEntity:myContentEntity insertIntoManagedObjectContext:managedObjectContext];

[contentToSave setValue:urlPicture forKey:@"url"];
[contentToSave setValue:person forKey:@"relatedPerson"];

[managedObjectContext insertObject:contentToSave]; 

NSError *error;
if ([managedObjectContext save:&error]){
 //Deal with errors
 NSLog(@"Error");
            return NO; 
}
return YES;
}

It crashes on the line if ([managedObjectContext save:&error]) and in the console I have those errors :

-[UITableViewCell objectID]: unrecognized selector sent to instance 0x135c2b0 Serious application error.  Exception was caught during Core Data change processing: ***     
-[UITableViewCell objectID]: unrecognized selector sent to instance 0x135c2b0 with userInfo (null) *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** 
-[UITableViewCell objectID]: unrecognized selector sent to instance 0x135c2b0'

and in my previous view I have the following code

- (void)viewDidLoad {
[super viewDidLoad];
SettingsSingleton *settings = [SettingsSingleton sharedManager]; 
managedObjectContext = [settings managedObjectContext]; 
fetchedResultsController = [settings fetchedResultsController];
fetchedResultsController.delegate=self;

NSError *error;
if (![[self fetchedResultsController] performFetch:&error]) {
 // Handle the error...
}
[settings release];

self.table = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 416)  style: UITableViewStyleGrouped];
[table setDataSource:self];
table.delegate=self;
[self.view addSubview: self.table];
}


- (NSFetchedResultsController *)fetchedResultsController {

if (fetchedResultsController != nil) {
    return fetchedResultsController;
}

Person *personTmp=[[Person alloc] init];
personTmp=[personTmp getPersonById:self.personId];

/*
 Set up the fetched results controller.
 */
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Pictures" inManagedObjectContext:managedObjectContext];
NSPredicate *predicate =[NSPredicate predicateWithFormat:@"relatedPerson == %@ AND contentType == %d",personTmp, CONTENT_DATA_PICTURE];

[fetchRequest setEntity:entity];
[fetchRequest setPredicate:predicate];

// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:@"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;

[aFetchedResultsController release];
[fetchRequest release];
[predicate release];
[personTmp release];


return fetchedResultsController;
}    


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *CellIdentifier = @"Cell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
 cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
 cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
if(indexPath.row==0){
    cell.textLabel.text=@"Add a picture";
}
else{
 int nb=indexPath.row-1;
 NSIndexPath *ip = [NSIndexPath indexPathForRow: nb inSection:indexPath.section];
 NSManagedObject *managedObject = [fetchedResultsController  objectAtIndexPath:ip];
 cell.textLabel.text = [[managedObject valueForKey:@"url"] description];
 [ip release];
}
return cell;
}


- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
int nb=[[fetchedResultsController sections] count];
if (nb == 0) {
    nb = 1;
}
return nb;
}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

NSArray *sections = [fetchedResultsController sections];
NSUInteger count = 0;
if ([sections count]) {
    id <NSFetchedResultsSectionInfo> sectionInfo = [sections objectAtIndex:section];
    count = [sectionInfo numberOfObjects];
}
return count+1;
}
+1  A: 

First, you do not have to call 'insertObject'. From the apple documentation:

If context is not nil, this method invokes [context insertObject:self] (which causes awakeFromInsert to be invoked).

So you are redundantly inserting the object twice. Not sure what negative effects this might have, but it can't be good.

As for the error, it looks like some other part of your code may be the culprit. What that message means basically is that you are trying to access the CoreData objectID of a UITableViewCell. Since this happens during the save, I imagine that at some point before this function, you may be inserting a UITableViewCell into the managedObjectContext, then you only blow out here when you actually go on to save it.

bobDevil
I have a different error now when I comment the code in the - (NSFetchedResultsController *)fetchedResultsController method I can add my pictures correctly else I have : Program received signal: “EXC_BAD_ACCESS”.
Mathieu
You're over-releasing predicate, and possibly the personTmp (depending on if getPersonById returns an autoreleased object or not). The crash is from either of these over-released objects. You should read up on Memory management in Objective-C (Google "Objective-c memory management", should be the first result). Additionally, if getPersonById returns a different person object, then you're also leaking the one you alloc-init'd right above that.
bobDevil
oh yeah, that works nowbut I have to release the predicate variable anyway, should I have to make it a global variable of the class and release it in the - (void)dealloc
Mathieu
No, just get rid of the release statement. It is autoreleased, so it will be deallocated for you. http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html
bobDevil
+1  A: 

Hi, I had a very similar error occurring. I had a navController loading customTypeA viewController first, then loading customTypeB viewController on top of that. Both of these viewControllers used Core Data and fetchedResultsControllers as the tableview's data source. customTypeB's function was to add a new data object to customTypeA's datasource. Upon doing so, I would receive the error you stated above "Serious Error in Core Data, Unrecognized Selector. EXC_BAD_ACCESS"; however my error stated that the unrecognized selector was "controllerWillChangeContent". Both of my viewControllers utilized the fetchedViewController delegate methods "controllerWillChangeContent, controllerDidChangeObject..., controllerDidChangeContent". I noticed that when viewControllerB changed controllerA's data, controllerA's fetchedResultsController activated even though controllerB had not yet been 'popped'. So I figured that perhaps controllerB's delegate was being called. Looking at the Core Data programming doc, I saw that they recommend for each view using fetchedResultsController, you should implement viewWillDisappear and inside it, set fetchedResultsController = nil; For me, this solved my problem.

Also FYI - I did not have this problems of the fetchedResultsControllers's delegates of non-visible viewControllers being called, prior to installed XCODE 3.2 for Snow Leopard. Code was working fine up in Xcode3.1 for Leopard.

pulseft
I'm with you. Basically, if you are using the same managedObjectContext in different viewControllers, and your fetchedViewController delegate is hooked in one of them, everything you change in data object will cause delegate methods get called.
digdog
In my dealloc, I forgot to `self.fetchedResultsController = nil;`. Doing that solved my problem. Doing in `viewWillDisappear:` and `viewWillAppear:` is probably overkill :)
Sam Soffes
After beating my head on `Serious application error. Exception was caught during Core Data change processing:` for days, I started googleing and found this again. Doing it in `viewDidDisappear:` and `viewWillAppear:` solved all of my problems. Messing with a non-visible NSFetchedResultsController does crazy stuff. I don't recommend it.
Sam Soffes