SIGBART on [[NSFetchedResultsController alloc] initWithFetchRequest - iphone

I receive a sigbart error on this line in my code:
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:#"ViewTwo"];
and this is the method:
- (NSFetchedResultsController *)fetchedResultsController
{
if (__fetchedResultsController != nil) {
return __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:#"MyData" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
// 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:self.managedObjectContext sectionNameKeyPath:nil cacheName:#"ViewTwo"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
NSError *error = nil;
if (![self.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.
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return __fetchedResultsController;
}
But this is a strange error, because in the console don't give me any explanation about it, so I can't understand what I am doing wrong.

NSFetchedResultsController needs a sort descriptor and a managed object context. You didn't provide a sort descriptor, so you'll have to give it that.

It's odd that there is no output for the SIGBART, try running the instruction (hitting step over see if it outputs.
What you need to do is check each element that you're sending to the method (by logging) it's probable one of them is actually nil or being dereferenced before the call executes.

You may modified your xcdatamodled but did not re-install your app on device.
Just delete the app builded on your device and build it again, everything will be OK.
Here is what apple say:
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.
Typical reasons for an error here include:
* The persistent store is not accessible;
* The schema for the persistent store is incompatible with current managed object model.
Check the error message to determine what the actual problem was.
If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.
If you encounter schema incompatibility errors during development, you can reduce their frequency by:
* Simply deleting the existing store:
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil]
Performing automatic lightweight migration by passing the following dictionary as the options parameter:
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.

Related

iPhone how to use NSPredicate to filter Core Data by the parent entity?

My core data is defined as this:
user has many events;
event has a single user relationship;
Both user and event are core data entities. The user entity is passed in through a storyboard segue.
I'm trying to configure NSPredicate to populate the detail UITableView for that user with only events for that particular user.
So far I have tried
//does not work
NSPredicate* onlyThisUserPredicate = [NSPredicate predicateWithFormat:#"user == %#",self.appUser];
//does not work
NSPredicate* onlyThisUserPredicate = [NSPredicate predicateWithFormat:#"SELF.user == %#",self.appUser];
What is the proper syntax to compare events and only return those that have user object equal to the specified user object?
UPDATE:
I'm trying to be able to add events to the user with this kind of fetched results controller:
-(NSFetchedResultsController*)fetchedResultsController
{
if (__fetchedResultsController != nil) {
return __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:#"Event" inManagedObjectContext:[Event managedObjectContext]];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
//I need to configure this user
NSPredicate* onlyThisUserPredicate = [NSPredicate predicateWithFormat:#"user = %#",self.appUser];
// The first sort key must match the section name key path key if present, otherwise the initial dataset would be messed up: rows in incorrect sections
NSString* firstSortKey = #"createDate";
NSSortDescriptor *firstSortDescriptor = [[NSSortDescriptor alloc] initWithKey:firstSortKey ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObjects:firstSortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[fetchRequest setPredicate:onlyThisUserPredicate];
// 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:[Event managedObjectContext] sectionNameKeyPath:nil cacheName:#"Events"];
self.fetchedResultsController = aFetchedResultsController;
aFetchedResultsController.delegate = self;
// [aFetchedResultsController release];
[sortDescriptors release];
[fetchRequest 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.
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
// abort();
}
return __fetchedResultsController;
}
Thank you!
OK, there are a couple of things that I can think of that might cause this behavior.
First, have you validated the value of self.appUser within this function? Is it set to what you expect?
Second, have you made sure your headers are all up to date and included in this file? Sometimes I've experienced odd behavior when my headers aren't up to date with the coredata model.
So this predicate is for the User entity correct? If so, did you try this:
NSPredicate* onlyThisUserPredicate = [NSPredicate predicateWithFormat:#"SELF == %#",self.appUser];
Then you could access your events through:
[self.appUser events];
If you've already retrieved the 'user' from the Core Data store, then you should be able to access its events simply by following that relationship -- no need to do a separate fetch request:
NSSet *events = self.appUser.events;
On the other hand, if self.appUser isn't a managed object, then using the == operator in your predicate is probably the problem. So let me assume that self.appUser is just a string containing the name of the user, not the user object from the data store. Then you'd use the 'like' operator in your predicate:
NSPredicate* onlyThisUserPredicate = [NSPredicate predicateWithFormat:#"user like %#",self.appUser];
Also, be sure that you've specified the right entity in your fetch request. For what you've described, you should be doing the fetch with the entity description for your event entity.

Sorting Core Data results into NSFetchedResultsController

I have an entity Tag with string property tagName. I went to fetch all objects in this Entity into a NSFetchedResultsController, but I want Tag with tagName "Main" to be the first object. Here's what I'm doing now:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"Tag" inManagedObjectContext:appDelegate.managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *lastDescriptor2 =
[[[NSSortDescriptor alloc] initWithKey:#"tagName" ascending:NO comparator:^NSComparisonResult(NSString* tag1, NSString* tag2) {
NSLog(#"compare");
if ([tag1 isEqualToString:#"main"]) return NSOrderedAscending;
if ([tag2 isEqualToString:#"main"]) return NSOrderedDescending;
return [tag1 compare:tag2];
}] autorelease];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:lastDescriptor2]];
NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:appDelegate.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
self.fetchedResultsController = theFetchedResultsController;
self.fetchedResultsController.delegate=self;
if (![[self fetchedResultsController] performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
This code is called in my viewDidLoad method, and is only called once. The first time it's called, for some reason the sortDescriptor here doesn't apply - it just doesn't get called (the NSLog statement doesn't show up either). My results are returning solely based on the BOOL value I specify for ascending - the block is ignored.
But when I insert a new Tag object into the MOC and the NSFetchedResultsController update delegate methods are called, the actual sortDescriptor gets applied, and the NSLog(#"compare") finally appears, but only when I make updates to the objects! No matter what I've tried, I can't get the sort to apply to the initial fetch.
Any ideas at all?
As you have probably seen at one point or another, if the predicate you pass into your NSFetchRequest is a block predicate, your fetch request will fail. This happens because CoreData needs to translate your predicate into SQL so it can run it against the database. The result is that a predicate is never actually compared against the objects that result from the fetch request.
The same is true of sort descriptors. The fetch request does not perform the comparison against the objects when the fetch is performed. It is passed as part of the SQL.
You also describe an interesting exception to the rules I describe above. When you have an existing NSFetchedResultsController and add an object to the NSManagedObjectContext, the NSFetchedResultsController is updated by evaluating the NSPredicate and NSSortDescriptor against the object, rather than converting them to SQL.

UITableView with huge(probably 1million entries)data in iphone

I am developing an application which requires loading of more than 1 million entries through infinite scrolling in a tableview. Each time request will be sent for 1000 entries and once data is downloaded and parsed through JSON library the table is reloaded. I have implemented this through CoreData with "setFetchBatchSize = 1000".
StreamModal *modal = [[StreamModal alloc]init];
StreamModal *modal = [NSEntityDescription insertNewObjectForEntityForName:#"StreamModal" inManagedObjectContext:managedObjectContext];
if([self isNotNull:[streamDataDict objectForKey:#"_id"]])
modal.stream_id = [streamDataDict objectForKey:#"_id"];
-(void)reloaData{
#try {
NSError *error;
if (![[self fetchedResultsController] performFetch:&error]) {
// Update to handle the error appropriately.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
exit(-1); // Fail
}
NSLog(#"ferchresults count %d",[[_fetchedResultsController fetchedObjects]count]);
}
#catch (NSException *exception) {
NSLog(#"exception raised in reloadData in streamViewController class %#",exception);
}
#finally {
}
}
- (NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"StreamModal" inManagedObjectContext:appDelegate.managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:#"date" ascending:NO];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
[fetchRequest setFetchBatchSize:1000];
//[fetchRequest setFetchLimit:2000];
NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:appDelegate.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
self.fetchedResultsController = theFetchedResultsController;
_fetchedResultsController.delegate = self;
fetchRequest = nil;
theFetchedResultsController = nil;
return _fetchedResultsController;
}
Here is the code i am using, when ever connectionfinishedloading data i am populating the data into NSManagedObject Class(StreamModal) and then calling reload data.Here the problem is the app is getting memory exceptions after i loaded 12000 entries in table and getting crashed. how can i load all entries without memory exception. i am new to CoreData concepts and have read the core data concepts through developer guide, but i didn't find any info related to memory handling. Please help me.
I hope you are using ARC? Because you're not releasing any initalized objects. (If not this is your answer.)
But anyway: Have you tried to use Instruments to see, which objects are increasing the memory footprint at most? That would be a good starting point.
shiva inturi,
First, I want to echo other comments that working with a single table view of a million items is really a bad user experience.
To your question:
What are you doing when the memory warning comes?
At minimum, you should be going through the objects array and trim the object graph. This is done with -refreshObject:mergeChanges:. You should also take care to not traverse your array very far. I would start from your visible objects and work both backwards and forwards until you start hitting faulted objects, by testing with -isFault.
Andrew

coredata sqlite malformed DB

I have problems with my coredata sqlite DB, which hosts a book DB. After a crash a user experiences has the problem, that the data isn't shown properly any more in his/her tableview.
This is due to the fact, that the performFetch method returns an error:
[NSFetchedResultsController deleteCacheWithName:nil];
if (![[self fetchedResultsController] performFetch:&error]) {
//NSArray *array = [[self fetchedResultsController] fetchedObjects];
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
#ifdef DEBUG
abort();
#endif
}
which results in this error message:
Unresolved error Error Domain=NSCocoaErrorDomain Code=134060 "The operation couldn’t be completed. (Cocoa error 134060.)" UserInfo=0x1dff80 {reason=The fetched object at index 312 has an out of order section name 'Z. Objects must be sorted by section name'}, {
reason = "The fetched object at index 312 has an out of order section name 'Z. Objects must be sorted by section name'";
When I have a look into the sqlite file with 'SQLite Database Browser 2.0 b1' the attributes of each entity seem to be ok.
When I delete some of the entities being mentioned everything works fine again.
I would like to know how I can find out what exactly is wrong with the mentioned entities and fix that, so the user can use his/her data again. Of course I want to fix the bug which causes the malformed DB as well but that is out of focus in this post.
Does anybody have any hints where I could have a look at or what might be malformed within my DB or what "an out of order section name" is?
This is the code for my fetchedResultsController:
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController != nil) {
return fetchedResultsController;
}
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity;
entity = [NSEntityDescription entityForName:#"Book" inManagedObjectContext:[[GlobalData sharedInstance] managedObjectContext]];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:10];
//set searchPredicate
NSPredicate *predicate = nil;
if (self.bibList != nil) {
predicate = [NSPredicate predicateWithFormat:#"ANY BibLists.name LIKE %#", self.bibList.name];
}
if (predicate) {
[fetchRequest setPredicate:predicate];
}
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor;
NSString *sortDescriptorString = nil;
sortDescriptorString = #"title";
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortDescriptorString ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSString *sectionNameKeyPath = nil;
sectionNameKeyPath = #"uppercaseFirstLetterOfTitle";
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController;
aFetchedResultsController = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:[[GlobalData sharedInstance] managedObjectContext]
sectionNameKeyPath:sectionNameKeyPath
cacheName:#"Bibliography"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
return fetchedResultsController;
}
Thanks
b00tsy
I think what is going on here is that your SQL store is corrupted and/or you have an unusual sectionNameKeyPath.
The Core Data schema prefixes all the SQL column names with Z so an error of a name of 'Z suggest a corrupted SQL table. To test for that, execute the fetch request directly instead of using the fetched results controller and see if you can fetch all the objects.
If you can't, then the SQL store is corrupted. Most likely, some table component is simply name 'Z instead of something like ZAttributeName. You will have to edit the SQL directly but that is tricky because of the custom private schema. See this post to get an idea what to look for. There are not any tools for doing this because corruption of the store is so rare.
If the fetch works then the problem is with the sectionNameKeyPath being handed to the fetched results controller. Right now, it looks like you have an entity attribute with the first letter of the title attribute. (This is redundant because by default, the FRC will automatically return alphabetic sections based on any string attribute.) Try changing the sectionNameKeyPath to just the title attribute name (most likely "title"). In any case, just dispense with the uppercaseFirstLetterOfTitle attribute altogether.
The following statement in the documentation hints at the error.
If this key path is not the same as that specified by the first sort descriptor in fetchRequest, they must generate the same relative orderings.
It seems that the item at index 312 is not in the correct section when sorting on title alone. This could be a result of the title property beginning with a non-letter or lowercase letter, which using lexical sorting would put it after the Z section but the value of the item's uppercaseFirstLetterOfTitle is not 'Z'. As a suggestion, try adding a sort descriptor on the uppercaseFirstLetterOfTitle as the first sort descriptor, then add the sort descriptor on title.

iPhone Core Data saving multiple items at once random behavior?

I have an application that reads an rss feed, parses the xml and adds it to my database using Core Data (this is so the user can see the feed even if no internet connection is available) this all works fine. The way I am doing the parsing is: on the didStartElement i create a new Entity such as:
NewsDB *newsDB = [NSEntityDescription insertNewObjectForEntityForName:#"NewsDB" inManagedObjectContext:managedObjectContext];
self.currentObject = newsDB;
and in the didendDocument i just save everything with something such as:
- (void)parserDidEndDocument:(NSXMLParser *)parser {
NSError *error = nil;
if (![managedObjectContext save:&error])
{
NSLog(#"Error saving %#", error);
}
This al works perfectly fine, in fact my program works just the way I want it now. But my question is when the managed object context gets saved the items seem to be added randomly, this is the first created object in the context may not be the first row in the database. I fixed this by adding a column that tells me the position in the xml, and then simply sorting by this column in my fetchedResultsController.
I know I could just save the context every time an item ends, but that doesn't sound like a good approach, so I just save them all at the end.
My question is why do they get added randomly?, is this the normal behavior?. Thank you.
-Oscar
The currency of Core Data are NSSet* instances. Sets are unordered, so anything you add and then fetch back will come back to you without any intrinsic ordering.
So you just need to apply an NSSortDescriptor when you initialize your NSFetchedResultsController. You can apply as many sort orderings as you like, e.g.:
NSSortDescriptor *lastNameDescriptor = [[NSSortDescriptor alloc] initWithKey:#"lastName" ascending:YES selector:#selector(caseInsensitiveCompare:)];
NSSortDescriptor *firstNameDescriptor = [[NSSortDescriptor alloc] initWithKey:#"firstName" ascending:YES selector:nil];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:lastNameDescriptor, firstNameDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[sortDescriptors release];
[lastNameDescriptor release];
[firstNameDescriptor release];
...
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:#"keyInitial" cacheName:#"MyObjects"];
self.fetchedResultsController = aFetchedResultsController;
self.fetchedResultsController.delegate = self;
[aFetchedResultsController release];
[fetchRequest release];
NSError *error;
if (![self.fetchedResultsController performFetch:&error]) {
// handle error...
}
This is normal behavior. You may have also noticed that when you create a to-many relationship that the related property is an unordered collection (NSSet).
When order matters, simply add a number attribute for sorting as you have done.