Crash when trying to get NSManagedObject from NSFetchedResultsController after 25 objects? - cocoa

I'm relatively new to Core Data on iOS, but I think I've been getting better with it. I've been experiencing a bizarre crash, however, in one of my applications and have not been able to figure it out.
I have approximately 40 objects in Core Data, presented in a UITableView. When tapping on a cell, a UIActionSheet appears, presenting the user with a UIActionSheet with options related to the cell that was selected. So that I can reference the selected object, I declare an NSIndexPath in my header called "lastSelection" and do the following when the UIActionSheet is presented:
// Each cell has a tag based on its row number (i.e. first row has tag 0)
lastSelection = [NSIndexPath indexPathForRow:[sender tag] inSection:0];
NSManagedObject *managedObject = [self.fetchedResultsController objectAtIndexPath:lastSelection];
BOOL onDuty = [[managedObject valueForKey:#"onDuty"] boolValue];
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:#"Status" delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil];
if(onDuty) {
[actionSheet addButtonWithTitle:#"Off Duty"];
} else {
[actionSheet addButtonWithTitle:#"On Duty"];
}
actionSheet.actionSheetStyle = UIActionSheetStyleBlackOpaque;
// Override the typical UIActionSheet behavior by presenting it overlapping the sender's frame. This makes it more clear which cell is selected.
CGRect senderFrame = [sender frame];
CGPoint point = CGPointMake(senderFrame.origin.x + (senderFrame.size.width / 2), senderFrame.origin.y + (senderFrame.size.height / 2));
CGRect popoverRect = CGRectMake(point.x, point.y, 1, 1);
[actionSheet showFromRect:popoverRect inView:[sender superview] animated:NO];
[actionSheet release];
When the UIActionSheet is dismissed with a button, the following code is called:
- (void)actionSheet:(UIActionSheet *)actionSheet willDismissWithButtonIndex:(NSInteger)buttonIndex {
// Set status based on UIActionSheet button pressed
if(buttonIndex == -1) {
return;
}
NSManagedObject *managedObject = [self.fetchedResultsController objectAtIndexPath:lastSelection];
if([actionSheet.title isEqualToString:#"Status"]) {
if([[actionSheet buttonTitleAtIndex:buttonIndex] isEqualToString:#"On Duty"]) {
[managedObject setValue:[NSNumber numberWithBool:YES] forKey:#"onDuty"];
[managedObject setValue:#"onDuty" forKey:#"status"];
} else {
[managedObject setValue:[NSNumber numberWithBool:NO] forKey:#"onDuty"];
[managedObject setValue:#"offDuty" forKey:#"status"];
}
}
NSError *error;
[self.managedObjectContext save:&error];
[tableView reloadData];
}
This might not be the most efficient code (sorry, I'm new!), but it does work. That is, for the first 25 items in the list. Selecting the 26th item or beyond, the UIActionSheet will appear, but if it is dismissed with a button, I get a variety of errors, including any one of the following:
[__NSCFArray section]: unrecognized selector sent to instance 0x4c6bf90
Program received signal: “EXC_BAD_ACCESS”
[_NSObjectID_48_0 section]: unrecognized selector sent to instance 0x4c54710
[__NSArrayM section]: unrecognized selector sent to instance 0x4c619a0
[NSComparisonPredicate section]: unrecognized selector sent to instance 0x6088790
[NSKeyPathExpression section]: unrecognized selector sent to instance 0x4c18950
If I comment out NSManagedObject *managedObject = [self.fetchedResultsController objectAtIndexPath:lastSelection]; it doesn't crash anymore, so I believe it has something do do with that. Can anyone offer any insight? Please let me know if I need to include any other information. Thanks!
EDIT: Interestingly, my fetchedResultsController code returns a different object every time. Is this expected, or could this be a cause of my issue? The code looks like this:
- (NSFetchedResultsController *)fetchedResultsController {
/*
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:#"Employee" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:80];
// Edit the sort key as appropriate.
NSString *sortKey;
BOOL ascending;
if(sortControl.selectedSegmentIndex == 0) {
sortKey = #"startTime";
ascending = YES;
} else if(sortControl.selectedSegmentIndex == 1) {
sortKey = #"name";
ascending = YES;
} else {
sortKey = #"onDuty";
ascending = NO;
}
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortKey ascending:ascending];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// Edit the section name key path and cache name if appropriate.
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:#"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
NSError *error = nil;
if (![fetchedResultsController_ performFetch:&error]) {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
*/
//NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return fetchedResultsController_;
}
This happens when I set a breakpoint:
(gdb) po [self fetchedResultsController]
<NSFetchedResultsController: 0x61567c0>
(gdb) po [self fetchedResultsController]
<NSFetchedResultsController: 0x4c83630>

It's prob the case that self.fetchedResultsController is pointing to the wrong memory location. You will need to check if the object has been retained.

Figured it out! Looks like it was an issue with autoreleased objects.
When I turned on NSZombieEnabled, I got this:
*** -[NSIndexPath section]: message sent to deallocated instance 0xa674530
I simply changed lastSelection = [NSIndexPath indexPathForRow:[sender tag] inSection:0]; to lastSelection = [[NSIndexPath indexPathForRow:[sender tag] inSection:0] retain]; and that took care of it.

Related

Correct way to get rearrangeObjects sent to an NSTreeController after changes to nodes in the tree?

What is the appropriate way to get rearrangeObjects to be sent to an NSTreeController after changes to nodes in the tree? I have a sample application (full code below) using an NSOutlineView and NSTreeController with a simple tree of Node objects.
In Version1 of the app, when you edit the name of a Node, the tree doesn't get resorted until you click the column header or use the “Rearrange” item in the menu. The latter is set up to directly send rearrangeObjects to the NSTreeController.
In Version2, I tried sending rearrangeObjects from the Node's setName: method. This doesn't seem like a good solution because it means the model now has knowledge of the view/controller. Also, it has the side effect that the outline view loses focus after the rename (if you select a Node and edit its name, the selection bar turns from blue to gray) for some reason (why is that?).
NSArrayController has a method setAutomaticallyRearrangesObjects: but NSTreeController does not? So what is the appropriate way to solve this?
/* example.m
Compile version 1:
gcc -framework Cocoa -o Version1 example.m
Compile version 2:
gcc -framework Cocoa -o Version2 -D REARRANGE_FROM_SETNAME example.m
*/
#import <Cocoa/Cocoa.h>
NSTreeController *treeController;
NSOutlineView *outlineView;
NSScrollView *scrollView;
#interface Node : NSObject {
NSString *name;
NSArray *children;
}
#end
#implementation Node
- (id) initWithName: (NSString*) theName children: (id) theChildren
{
if (self = [super init]) {
name = [theName retain];
children = [theChildren retain];
}
return self;
}
- (void) setName: (NSString*) new
{
[name autorelease];
name = [new retain];
#ifdef REARRANGE_FROM_SETNAME
[treeController rearrangeObjects];
#endif
}
#end
NSArray *createSortDescriptors()
{
return [NSArray arrayWithObject: [NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES]];
}
void createTheTreeController()
{
Node *childNode1 = [[[Node alloc] initWithName:#"B" children:[NSArray array]] autorelease];
Node *childNode2 = [[[Node alloc] initWithName:#"C" children:[NSArray array]] autorelease];
Node *childNode3 = [[[Node alloc] initWithName:#"D" children:[NSArray array]] autorelease];
Node *topNode1 = [[[Node alloc] initWithName:#"A" children:[NSArray arrayWithObjects:childNode1,childNode2,childNode3,nil]] autorelease];
Node *topNode2 = [[[Node alloc] initWithName:#"E" children:[NSArray array]] autorelease];
Node *topNode3 = [[[Node alloc] initWithName:#"F" children:[NSArray array]] autorelease];
NSArray *topNodes = [NSArray arrayWithObjects:topNode1,topNode2,topNode3,nil];
treeController = [[[NSTreeController alloc] initWithContent:topNodes] autorelease];
[treeController setAvoidsEmptySelection:NO];
[treeController setChildrenKeyPath:#"children"];
[treeController setSortDescriptors:createSortDescriptors()];
}
void createTheOutlineView()
{
outlineView = [[[NSOutlineView alloc] initWithFrame:NSMakeRect(0, 0, 284, 200)] autorelease];
[outlineView bind:#"content" toObject:treeController withKeyPath:#"arrangedObjects" options:nil];
[outlineView bind:#"sortDescriptors" toObject:treeController withKeyPath:#"sortDescriptors" options:nil];
[outlineView bind:#"selectionIndexPaths" toObject:treeController withKeyPath:#"selectionIndexPaths" options:nil];
NSTableColumn *column = [[[NSTableColumn alloc] initWithIdentifier:#"NameColumn"] autorelease];
[[column headerCell] setStringValue:#"Name"];
[outlineView addTableColumn:column];
[outlineView setOutlineTableColumn:column];
[column bind:#"value" toObject:treeController withKeyPath:#"arrangedObjects.name" options:nil];
[column setWidth:250];
scrollView = [[[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 300, 200)] autorelease];
[scrollView setDocumentView:outlineView];
[scrollView setHasVerticalScroller:YES];
}
void createTheWindow()
{
id window = [[[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 300, 200)
styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:NO]
autorelease];
[window cascadeTopLeftFromPoint:NSMakePoint(20,20)];
[window setTitle:#"Window"];
[window makeKeyAndOrderFront:nil];
[[window contentView] addSubview:scrollView];
}
void createTheMenuBar()
{
id menubar = [[NSMenu new] autorelease];
id appMenuItem = [[NSMenuItem new] autorelease];
[menubar addItem:appMenuItem];
[NSApp setMainMenu:menubar];
id appMenu = [[NSMenu new] autorelease];
#ifndef REARRANGE_FROM_SETNAME
id rearrangeMenuItem = [[[NSMenuItem alloc] initWithTitle:#"Rearrange"
action:#selector(rearrangeObjects) keyEquivalent:#"r"] autorelease];
[rearrangeMenuItem setTarget: treeController];
[appMenu addItem:rearrangeMenuItem];
#endif
id quitMenuItem = [[[NSMenuItem alloc] initWithTitle:#"Quit"
action:#selector(terminate:) keyEquivalent:#"q"] autorelease];
[appMenu addItem:quitMenuItem];
[appMenuItem setSubmenu:appMenu];
}
void setUpAutoReleasePoolAndApplication()
{
[NSAutoreleasePool new];
[NSApplication sharedApplication];
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
}
void activateAppAndRun()
{
[NSApp activateIgnoringOtherApps:YES];
[NSApp run];
}
int main(int argc, const char * argv[])
{
setUpAutoReleasePoolAndApplication();
createTheTreeController();
createTheOutlineView();
createTheWindow();
createTheMenuBar();
activateAppAndRun();
return 0;
}
I'm at least able to partly answer my own question after having looked at Apple's iSpend sample application. Their file TransactionsController_Sorting.m includes a method scheduleRearrangeObjects that invokes rearrangeObjects in a different way. Changing my own code in the same way means including this snippet in the setName: method:
#ifdef REARRANGE_FROM_SETNAME
// Commented out: [treeController rearrangeObjects];
[treeController performSelector:#selector(rearrangeObjects) withObject:nil afterDelay:0.0];
#endif
With this change, the outline view no longer loses focus after renaming a node. What's left to do now is take this code out of the model and into the view/controller; TransactionsController_Sorting seems to also illustrate how to do that. (I still don't understand why the above change prevents the outline view from losing focus though, anyone have an explanation?)
Another answer, as a possible explanation
I believe rearrangeObjects and fetch are delayed until the next runloop iteration. fetch at least tells you so in the docs:
Special Considerations
Beginning with OS X v10.4 the result of this method is deferred until the next iteration of the runloop so that the error presentation mechanism can provide feedback as a sheet.
In my own experimentation, I can use dispatch_async after rearrangeObjects to get code executed after the rearrange. In other words, if I don't dispatch_async code following rearrangeObjects it will be applied before the deferred rearrange. It's a great way to tear out your hair.
In any event, I suspect you were losing focus because rearrangeObjects blows away the context in which you were editing a node as it reloads the whole object tree, but if you force it to execute immediately, you don't lose that context.
[edit] Update here. I was dealing with rearrangeObjects and core data not seeming synchronous, and sure enough, it isn't. I caught an arrayController calling dispatch_async through a binding stack trace.

NSRangeException in didSelectRowAtIndexPath for iPad app

Working on an app that populates a table based on clicking on a cell from another table. So, I click on the (table named)Recipe, and an second table (Ingredients) is populated. I'm pulling the data from a sqlite DB using core data. When I select the first recipe, the ingredients populate no problem. Selecting any other recipe results in the NSRangeException error.
Code:
- (void)tableView:(UITableView*)aTableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
UITableViewCell *cell = (UITableViewCell *)[(UITableView *)srcTableView cellForRowAtIndexPath:indexPath];
NSLog(#"didSelectRowAtIndexPath: row=%i",indexPath.row);
MealPlanItAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSEntityDescription *entityDesc = [NSEntityDescription entityForName:#"Ingredients" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];
NSLog(#"Cell: %#", cell.textLabel.text);
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(RecipeID = %#)", cell.textLabel.text];
[request setPredicate:pred];
NSManagedObject *matches = nil;
NSError *error;
NSArray *objects = [context executeFetchRequest:request error:&error];
if ([objects count] == 0)
{
NSLog(#"No matches");
dtlData = [[NSMutableArray alloc] initWithArray:nil];
[dtlTableView reloadData];
} else {
NSLog(#"Match found");
dtlData = [[NSMutableArray alloc] initWithArray:nil];
[dtlTableView reloadData];
matches = [objects objectAtIndex:0];
for(matches in objects)
{
[dtlData insertObject:[matches valueForKey:#"Ingredient"] atIndex:indexPath.row];
[dtlTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[dtlTableView reloadData];
}
}
[request release];
}
It explodes at the line near the end:
[dtlData insertObject:[matches valueForKey:#"Ingredient"] atIndex:indexPath.row];
with an error: * Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayM insertObject:atIndex:]: index 4 beyond bounds for empty array'
Where the index 4 is the 4th cell clicked...so it always corresponds with the cell row.
Using the NSLog, the data is returned by the call and returned into 'objects' with the appropriate counts.
And, like I said, it works when clicking the first cell but no other cell. I can click multiple times on the first cell and it continues working. So, it has something to do with the 0 index (I suspect) but can't figure what.
If I replace the line
[dtlData insertObject:[matches valueForKey:#"Ingredient"] atIndex:indexPath.row];
with
[dtlData insertObject:[matches valueForKey:#"Ingredient"] atIndex:0];
I get the exact same behavior.
Any thoughts?
Nothing is wrong with the UITable View Code (as i had a quick look over that, just wondering why are you allocating the Array on every click of the table view cell? Initialize the array once, and handle add or removal of objects appropriately). Anyways, coming to your question : The issue is due to using
[array insertobject:]
The reason is that the array is initialized by a NILL object and when you try to insert object at index n, it complaints that the array is empty as the indexes < n are all NIL. So instead of using [array insertobject:atindex:], i would suggest you to simply call [array addobject:] this will add the objects at consecutive locations and will resolve the crash.

Download Images, Display Them in UIImageView, and SORT

Ok guys, I am fairly new to objective C. I have an app that downloads a list of images from my web server and displays the appropriate ones in a UIImage view with swipe gestures to go forward or backwards for the next/previous pic to be displayed. Current naming format for the pictures is like this:
uploaded_141_admin1.png
uploaded_141_admin2.png
uploaded_141_interior1.png
uploaded_141_interior2.png
uploaded_141_exterior1.png
The current code loads every picture into the view that has 141 in the middle part of the filename (or whatever record the user in on... 141 is variable in this instance, just showing here for an example of the format). The problem is, there seems to be no rhyme or reason as to what order they are displayed in. I would like it to use the last part of the filename to sort alphabetically (or even the whole filename, as it would achieve the same result). In the example above, it would display the downloaded pics in the following order when swiping through the uiimageiew:
uploaded_141_admin1.png
uploaded_141_admin2.png
uploaded_141_exterior1.png
uploaded_141_interior1.png
uploaded_141_interior2.png
I've search and can't find what I am looking for (maybe because I'm using the wrong search criteria). Here is my existing code that downloads and displays the images in the UIImageView. I assume the "sort" code would go in here somewhere:
-(void)downloadPictures:(NSArray *)picPaths {
ELog(#"Downloading pictures: %#",picPaths);
// wait indicator
[[WaitingView sharedInstance] setMessage:LocStr(#"Loading pictures... The more pictures there are, the longer this will take. Please be patient.")];
[[WaitingView sharedInstance] showIndicator:YES];
[[WaitingView sharedInstance] displayOn:[self view]];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
// queue download operation
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSInvocationOperation *downloadOp = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(downloadOperation:) object:picPaths];
[queue addOperation:downloadOp];
}
-(void)downloadOperation:(NSArray *)picPaths {
NSMutableArray *allPictures = [[NSMutableArray alloc] init];
for(NSString *path in picPaths) {
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://%#%#/%#/%#",SERVER_ADDRESS,SERVER_PORT,SERVER_PHOTOS,path]];
NSData *picData = [NSData dataWithContentsOfURL:url];
if(picData!=nil) {
UIImage *img = [UIImage imageWithData:picData];
if(img!=nil) {
[allPictures addObject:img];
} else {
ELog(#"Failed to convert data to image from url %#",url);
}
} else {
ELog(#"Failed to download image from url %#",url);
}
}
[[WaitingView sharedInstance] performSelectorOnMainThread:#selector(remove) withObject:nil waitUntilDone:NO];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
self.pictures=allPictures;
if([self.pictures count]==0) {
[self performSelectorOnMainThread:#selector(downloadErrorMessage) withObject:nil waitUntilDone:NO];
} else {
self.currentIndex=0;
[self performSelectorOnMainThread:#selector(showPicture) withObject:nil waitUntilDone:NO];
}
}
-(void)downloadErrorMessage {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Oooops!" message:LocStr(#"Pictures download failed") delegate:nil cancelButtonTitle:LocStr(#"Close") otherButtonTitles:nil];
[alert show];
[alert release];
[self goBack];
}
-(void)showPicture {
UIImage *image = [self.pictures objectAtIndex:self.currentIndex];
ELog(#"Now displaying image with index %d: %#",self.currentIndex,image);
self.picture.image=image;
[self.picture setNeedsLayout];
}
In your downloadPictures: method you should sort your picPaths array to be the order you want the images before you start the download operation. You can do this by creating a new sorted array using the NSArray method sortedArrayUsingSelector:. Using caseInsensitiveCompare: as the selector for the sort will order the NSStrings in the array alphabetically.
NSArray *sortedPicPaths = [picPaths sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
Then when you init your NSInvocationOperation, pass the sorted array as the object.

UITableViewController viewWillAppear

I have a view controller that is a subclass of UITableViewController. Here is my viewWillAppear:animated method:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (fetchedResultsController != nil) {
[fetchedResultsController release];
fetchedResultsController = nil;
}
[self.fetchedResultsController performFetch:nil];
[self.tableView reloadData];
}
I am getting confused by seeing the fetchedResultsController being accessed when [super viewWillAppear:animated] is called. Since super is a UITableViewController, and there is no viewWillAppear:animated method for that class, per se, then its superclass viewWillAppear:animated should be called, right? If that's correct, then the UIViewController class should not be accessing UITableViewController delegate methods. But I see that numberOfSectionsInTableView is getting called. I'm not sure why the call to super viewWillAppear:animated would do this.
So before I explicitly run the peformFetch and reloadData, the table is getting populated. At that time, the data it is being populated with is out of date.
Here is the fetchedResultsController code
- (NSFetchedResultsController *) fetchedResultsController {
if (fetchedResultsController != nil) {
return fetchedResultsController;
}
NSFetchRequest *fetchRequest = ...
NSEntityDescription * entity = ...
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:10];
NSSortDescriptor *aSortDescriptor = ...
NSSortDescriptor *bSortDescriptor = ...
NSArray *sortDescriptors = ...
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = ...
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
...
[sortDescriptors release];
NSError *error = nil;
if (![fetchedResultsController performFetch:&error]) {
NSLog(#"Unresolved Error %#, %#", error, [error userInfo]);
abort();
}
return fetchedResultsController;
}
The documentation specifically describes this behaviour:
When the table view is about to appear the first time it’s loaded, the table-view controller reloads the table view’s data. It also clears its selection (with or without animation, depending on the request) every time the table view is displayed. The UITableViewController class implements this in the superclass method viewWillAppear:. You can disable this behavior by changing the value in the clearsSelectionOnViewWillAppear property.

Core Data fetchedResultsController errors 'A fetch request must have an entity' entityForName returns nil

Hi I set up my own coredata app, or I tried...
First I created the xdatamodel and generated the Modelclasses, after this I implemented all the function of core-data in AppDelegate which I found in a generated project. Finally I copied the fetchedResultsController in my TableViewController.
fetchedResultsController
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController_ != nil) {
return fetchedResultsController_;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"ParameterGroup" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:#"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
NSError *error = nil;
if (![fetchedResultsController_ performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return fetchedResultsController_;
}
First I checked if the managedObjectsController is != nil, it has a address
Then I copied the EntityName from my xdatamodel in entityForName,
but NSEntityDescricption entity is nil.
And if I just create a new object the exception says, that the entity doesn't exist
Do I have to connect the xdatamodel to my project?
Hope you can help me
Thanks a lot!!!
The most common cause of this problem is simply misspelling the entity name wrong in the code such that it doesn't match the entity name in the data model.
Copy and paste the entity name from the model to the code and see if that fixes the problem.
The simplest way to solve this, given that you haven't done a lot coding on non-core-data parts, is probably to create a new project where you check the box for "Use Core Data". If you're going to use a Navigation Bar, choose this as your template. If I recall correctly, this will generate a table view with all functions needed. You'll have to modify the datamodel (generated).
Remark that you'll have to delete the app from the Simulator if it is installed and you change the datamodel (otherwise the generated data will not be consistent with the datamodel and the app will crash)

Resources