Core Data: deleteObject crashes application, NSPredicate the cause? - ios

I'm using a UICollectionView along with Core Data.
I can't seem to figure out why I can't remove an object from Core Data. It crashes at [self.managedObjectContext deleteObject:animation]; with an index 0 beyond bounds for empty array error. The following method is a delegate method that gets invoked from another viewcontroller. It gets a timestamp NSInteger and should create an NSPredicate with that timestamp.
The strange thing is that when I take the animationTimestamp NSInteger and hardcode it like:
[NSPredicate predicateWithFormat:#"timestamp == %i", #"1370169109"] it works and the object gets deleted without the error. However, when I want to pass the parameter as the argument it crashes. I've tried making it a string, NSNumber etc. Nothing works when I take the parameter, it only does when I hardcode it. I've logged animationTimestamp and it shows the correct value, so I'm stuck.
Thanks!
- (void)deleteAnimationWithTimestamp:(NSInteger)animationTimestamp {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Animations" inManagedObjectContext:self.managedObjectContext];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"timestamp == %i", animationTimestamp];
[fetchRequest setPredicate:predicate];
[fetchRequest setEntity:entity];
NSError *error;
NSArray *animations = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
for (NSManagedObject *animation in animations) {
[self.managedObjectContext deleteObject:animation];
}
// Save core data
if (![self.managedObjectContext save:&error]) {
NSLog(#"Couldn't save: %#", [error localizedDescription]);
}
[self.animationsCollectionView reloadData];
}
EDIT:
More info that might matter. The timestamp attribute in the model is a 64 bit integer (should it be by the way?). When I create the object I use:
NSNumber *timestampNumber = [NSNumber numberWithInt:timestamp];
[newAnimation setValue:timestampNumber forKey:#"timestamp"];

Get the NSInteger value from NSNumber
Like
NSInteger timestampNumber = [[NSNumber numberWithInt:timestamp] integerValue];
// then use this integer
[newAnimation setValue:timestampNumber forKey:#"timestamp"];
// or in
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"timestamp == %d", timestampNumber];

Related

NSPredicate weird crash with NSString

I'm trying to get a CoreData entity based on her name, to do that a created a method, that accepts a name parameter (NSString), so this is the method:
-(void)pegarCategoryByName:(NSString *)catName {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]init];
NSLog(#"Category Name: %#", catName);
NSError *error = nil;
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Categorias" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"categoria == '%#'", catName];
[fetchRequest setPredicate:predicate];
// [fetchRequest setFetchLimit:1];
NSArray *fetchedObjects = [[self managedObjectContext]executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects.count > 0) {
_categoriaAtual = [fetchedObjects objectAtIndex:0];
} else {
NSLog(#"Category not Found");
}
}
So lets say i call somewhere in my code:
[self pegarCategoryByName:#"Songs"];
When i run i get the NSLog: Category Name Songs, Category not Found and them the App crashes.
The weird part is, if i change the NSPredicate on pegarCategoryName to not use the NSString passed, here's and example:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"categoria == 'Songs'"];
Everything works just fine.
Do not enclose the %# placeholder in the predicate format in quotation marks:
[NSPredicate predicateWithFormat:#"categoria == %#", catName];
catName is already a string; you don't need to surround it with quotes, it would be the same as:
categoria == '#"Songs"'
so remove them:
#"categoria == %#"

Integer Comparison through Predicate

I am using core data in which I am having an entity called "Scan" who is having one attribute say electronic_id which is of NSNumber type. Now suppose in data base i am having 3 entries of this Scan attribute.
One entry of this entity having 35 as electronic_id.
Second entry of this entity having 354 as electronic_id.
Third entry of this entity having 375 as electronic_id.
I am performing searching on this attribute. so I when i start to search entity by passing 3 i want all these 3 objects.when i pass 35 then i want first two objects.
I want partial matches objects on NSNumber through predicate.
I am using this function.
-(void)filteredContentWithSearchText:(NSString*)searchText
{
if([searchText length])
{
int value=0;
value=[searchText intValue];
if ([strSelectedType isEqualToString:#"Electronic ID"])
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"electronic_id == %d",value];
NSManagedObjectContext *context =[self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Scan" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:predicate];
NSError *error=nil;
NSArray *results = [context executeFetchRequest:fetchRequest error:&error];
if (error==nil)
{
}
else if (error!=nil)
{
NSArray *results =[APP_DELEGATE CallForGetScan:YES Predicateis:predicate];
[arrSessionSearchData removeAllObjects];
[arrSessionSearchData addObjectsFromArray:results];
}
}
}
}
Please help how to compare integer in NSPredicate.
Thanks in Advance.
Try cast integer to string and compare it
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"electronic_id.stringValue CONTAINS[c] %#",searchText];
#sage444 your answer is what I have looking for hours. Works like a charm.
I just provide Swift version for future readers:
let predicate = NSPredicate(format: "%K.stringValue CONTAINS[c] %#",
#keyPath(YOUR_MODEL.number),
substring)

Core data - NSFetchrequest fetching twice the actual count of data

NSFetchRequest in the below code is fetching in multiples times count of the data.. Example I have 3 as array count 1st time the method is called, next time it become 6 next 9 and so on. But in the database, the count remains as 3. Why is this happening?
// the method is called in viewDidLoad
- (void) create {
[orderList removeAllObjects];
NSError * error;
NSEntityDescription *entity = [NSEntityDescription entityForName:#"OrderList"
inManagedObjectContext:context];
for (int addOrd = 0; addOrd < orderMainArray.count; addOrd++) {
GetOrders *getOrd = (GetOrders*)[NSEntityDescription insertNewObjectForEntityForName:#"GetOrders" inManagedObjectContext:context];
OrderList *ordList = (OrderList*)[NSEntityDescription insertNewObjectForEntityForName:#"OrderList" inManagedObjectContext:context];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"orderId contains[cd] %#", [[orderMainArray objectAtIndex:addOrd] objectForKey:#"orderId"]];
[fetchRequest setPredicate:predicate];
[fetchRequest setEntity:entity];
NSLog(#"\n \n \n count for same data = %d", [context countForFetchRequest:fetchRequest error:&error]);
if ([context countForFetchRequest:fetchRequest error:&error] ==0 ) {
// all data is saved here
[getOrd addOrderListObject:ordList];
if ([context save:&error]) {
NSLog(#"The save was successful! %#", ordList.orderId);
}
else {
NSLog(#"The save wasn't successful: %#", [error userInfo]);
}
}
}
NSFetchRequest *fetchRequest1 = [[NSFetchRequest alloc] init];
[fetchRequest1 setEntity:entity];
orderList = [[context executeFetchRequest:fetchRequest1 error:&error] mutableCopy]; // array count increases every time the method is called
}
Each time I call insertNewObjectForEntityForName:InManagedObjectContext: I was creating and adding new objects. So changed that and now works fine.
The code mixes fetch requests and inserts of new managed objects.
You insert one OrderList NSManagedObject and one GetOrder NSManagedObject in each iteration of the for-loop. Given your description, I would assume that orderMainArray.count has a value of 3.

NSPredicate for simple fetchRequest

I am using Core Data to save previous searches in a SearchBar. My entity is very simple, it just has the property:
previousSearch (NSString)
When the user types in the search bar, I want to search the database for my previous search. I keep getting 0 results though.
Here is the code that retrieves the data from Core Data.
- (void)filterContentForSearchText:(NSString *)searchText {
[self.filteredLastSearches removeAllObjects];
NSEntityDescription *search = [NSEntityDescription entityForName:#"Search" inManagedObjectContext:_managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:search];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"previousSearch=[c]%#", searchText];
[fetchRequest setPredicate:predicate];
NSError *error = nil;
NSArray *fetchedObjects = [_managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (error) {
NSLog(#"Error filtering search: %#", [error description]);
}
_filteredLastSearches = [NSMutableArray arrayWithArray:fetchedObjects];
}
fetchedObjects is always empty and I'm not sure why. I can see in the database that the db actually has the ZPREVIOUSSEARCH with a couple values that I've tried to show while searching, but it's always empty. Is there something I'm missing? Thanks in advance.
I'm not sure if = operator work with [c]. Try to use like instead:
[NSPredicate predicateWithFormat:#"previousSearch like[c] %#", searchText];
Also you may want to search not equal results but results that contains (or begins with) your text. In this case you may use contains or beginswith.
[NSPredicate predicateWithFormat:#"previousSearch contains[c] %#", searchText];
[NSPredicate predicateWithFormat:#"previousSearch beginswith[c] %#", searchText];

How To Format NSPredicate when doing an "IN" search with Coredata and NSFetchRequest

I have a very simple fetch request that i want to execute. One of my entities has an attribute called smartCollectionIds and it is of type transformable. I use this attribute to store an NSArray of simple strings. In my code i use an NSfetchedResultsController to populate a tableview. The predicate im using is as follows:
predicate=[NSPredicate predicateWithFormat:#"smartCollectionIds!=nil && (%# IN smartCollectionIds)",#"87F173A5-863D-4ECE-9673-A61D8F1E01FC-6285-000009A9CBAF3290"];
however this causes a crash, specifically at the pint when i perform a fetch. However, if i first use a fetch to load all my objects into an array, and then filter them out with the above predicate, the app does not crash, and i get my results as expected. So basically
THIS CODE BELOW DOES NOT WORK
-(void) tryTO
{
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Tweetary" inManagedObjectContext: [[ChubbyEyetwitterEngine sharedInstance] getManagedObjectContextForUse]];
NSPredicate *predicate;
predicate=[NSPredicate predicateWithFormat:#"smartCollectionIds!=nil && (%# IN smartCollectionIds)",#"87F173A5-863D-4ECE-9673-A61D8F1E01FC-6285-000009A9CBAF3290"];
NSSortDescriptor *secondarySortKey = [[[NSSortDescriptor alloc] initWithKey:#"created_at" ascending:FALSE] autorelease];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease] ;
[request setEntity:entity];
[request setPredicate:predicate];
[request setSortDescriptors:[NSArray arrayWithObjects:
secondarySortKey
,nil]];
[request setFetchLimit:30]; //30
NSError *error;
NSArray *results = [[[ChubbyEyetwitterEngine sharedInstance] getManagedObjectContextForUse] executeFetchRequest:request error:&error];
if (error != nil)
{
NSLog(#"Results are %d",[results count]);
}else{
NSLog(#"findAllObjectsInContext error %#",error);
}
}
BUT THIS WORKS
NSArray *tweets = [Tweetary findAllObjectsInContext:[[ChubbyEyetwitterEngine sharedInstance] getManagedObjectContextForUse]];
NSLog(#"Before filter count is %d",[tweets count]);
predicate=[NSPredicate predicateWithFormat:#"smartCollectionIds!=nil && (%# IN smartCollectionIds)",#"87F173A5-863D-4ECE-9673-A61D8F1E01FC-6285-000009A9CBAF3290"];
predicate=[NSPredicate predicateWithFormat:#"smartCollectionIds!=nil && (%# IN smartCollectionIds)",#"87F173A5-863D-4ECE-9673-A61D8F1E01FC-6285-000009A9CBAF3290"];
NSArray *bNames = [tweets filteredArrayUsingPredicate:predicate];
NSLog(#"FINAL Results %d",[bNames count]);
+ (NSArray *)findAllObjectsInContext:(NSManagedObjectContext *)context;
{
#synchronized(self){
NSEntityDescription *entity = [self entityDescriptionInContext:context];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:entity];
NSError *error = nil;
NSArray *results = [context executeFetchRequest:request error:&error];
if (error != nil)
{
//handle errors
//NSLog(#"findAllObjectsInContext error %#",error);
}
return results;
}
}
In a nutshell, i need my fetch predicate to work when using NSfetchedResultsController instead of first loading up my objects into an array, and then applying my filter predicate. Can anyone point me in the right direction/ figure out why the predicate works only after i load my unfiltered data set into an array?
A Core Data fetch request with a predicate is translated to a SQLite query and executed
on the SQLite level. A transformable array is stored as some blob in the SQLite database,
therefore treating it as array in a fetch request does not work.
If you fetch the elements first, the blob is transformed back to an array
when the property is accessed. Therefore filtering the array of fetched objects works as expected.
I don't think there is any workaround. You cannot filter on transformable properties
in a fetch request.

Resources