NSPredicate for matching property - objective-c

What in the world am I doing wrong here? Frustrated beyond belief.
I have an array that contains a certain type of object with a property. We'll just call that property "number". It is of type NSUInteger.
I also have an entity that has an attribute of "number", with a type of Integer 64.
I'm trying to create a fetch request that finds me all the objects in my Core Data store that do not exist in the other array with objects.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
fetchRequest.entity = [NSEntityDescription entityForName:#"EntityName" inManagedObjectContext:context];
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"NOT (%#.number IN number)",someArrayWithObjects];
NSError *error = nil;
NSArray *notMatchingObjects = [context executeFetchRequest:fetchRequest error:&error];
This returns a nil array. I know that I have objects with numbers in my local store that do not exist in my other array. Am I doing something wrong?

Use the fact that NSArrays are key-value coding compliant and will give you an array of property values with valueForKey: (For NSUInteger it will wrap them in NSNumbers)
NSArray *predicateInts = [someArrayWithObjects valueForKey:#"number"];
[NSPredicate predicateWithFormat:#"NOT (number IN %#)",predicateInts];

First you have to create an array of NSNumber objects that contains just the numbers that you want to exclude.
Then you can use the following fetch request:
[NSPredicate predicateWithFormat:#"NOT (number IN %#)", arrayWithNumbers];

Related

Why can I not get a properly formatted string from NSArray element?

I'm trying to retrieve an attribute from my core data model and put the acquired string into the title of my navigation bar. I must be doing something wrong, as I cannot set my retrieved string as the title, yet I can set the title if I manually enter the string.
Here is how I am retrieving from Core Data:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Area" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
//set predicate
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"identifier == %#", self.area_id];
NSArray *area = [context executeFetchRequest:fetchRequest error:&error];
NSString *area_name = [area valueForKey:#"name"];
NSString *test = #"test";
NSLog(#"%#",test);
NSLog(#"%#",area_name);
When I set the title using self.tabBarController.title = area_name; I get "NSArrayI stringByTrimmingCharactersInSet:]: unrecognized selector sent to instance" and it sets just fine when I set it to the test variable.
I also noticed that the NSLog for the variable test is "test" whereas the NSLog output for area_name is: ( "Single Area" )
Is this because of how I am retrieving my area_name from the array? Should I be using a dictionary instead? Forgive me for my ignorance, I'm fairly new to obj-c.
Thanks.
Here is mistake
NSString *area_name = [area valueForKey:#"name"];
area object is type of NSArray which contains Area objects.
So you need to get element from that array, and then read name.
Area *firstArea = [area firstObject];
NSString *area_name = firstArea.name;
NSLog(#"%#",area_name);
Change the predicate to this:
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"identifier = %#", self.area_id];
I suppose than self.area_id is init correctly.

Boolean values and core data

I have Boolean values in a entity, the values are all show 0.
The values are fetched and no matter what I always get back a TRUE value.
Here is the code, the problem is probably at the last 2 lines of code.
What am I doing wrong?
-(NSInteger)getStatus:(NSString*)nameID;
{
**//Fetch Request**
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity =
[NSEntityDescription entityForName:#"status"
inManagedObjectContext:[self managedObjectContext]];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate
predicateWithFormat:#"id_Name = %#", nameID];
[fetchRequest setPredicate:predicate];
NSError *error = nil;
NSArray *fetchedObjects = [[self managedObjectContext] executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
}
**//Values**
status *ENT_status;
ENT_status = [fetchedObjects objectAtIndex:0];
//Either way, both these lines return YES when it would be NO
//------------------------------------------------------------------
BOOL one = ENT_status.status_one;
NSNumber *two = [NSNumber numberWithBool:ENT_status.status_two];
By default, boolean values are represented as NSNumber objects in the managed objects.
So you can either use it as it is:
NSNumber *one = ENT_status.status_one;
or convert it to a plain (scalar) BOOL:
BOOL one = [ENT_status.status_one boolValue];
(In your code, the pointer ENT_status.status_one is always interpreted as YES.)
Alternatively, you can use the option "Use scalar properties for primitive data types"
when creating the managed object subclass in Xcode.
I know its a bit late and probably no one is using Objective-C anymore but i came across this problem and what worked for me was:
to retrieve a boolean value from object:
BOOL myBool = [[myManagedObject valueForKey:#"myKey"] boolValue];
and to set the new value:
myManagedObject.myKey = #YES;

Problems with Boolean type attribute in Core Data with predicates in Xcode

Okay, so I already tried the examples on apple's SDK developer pages and it didn't work. I tried the examples from previous questions on stackoverflow like :
NSEntityDescription entitydesc = [NSEntityDescription entityForName:#"Model" inManagedObjectContext:context];
NSFetchRequest request = [[NSFetchRequest alloc]init];
[request setEntity:entitydesc];
//tried this style of predicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"accessible == %#", [NSNumber numberWithBool:YES]];
//and this one
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"accessible == YES"];
[request setPredicate: predicate];
NSError *error;
NSArray *matchingData = [context executeFetchRequest: request error: &error];
both of which didn't work. In debugger the matchingData shows 0 objects when it should have many.
All my other fetchrequests have worked perfectly fine. This is the only one giving me problems.
The attribute is listed as type Boolean in the .xcdatamodel
The attribute is listed as this under the entity's header file:
#property (nonatomic, retain) NSNumber * accessible;
The data was entered into the core data database as follows:
NSNumber *accessibleFieldValue = [NSNumber numberWithBool:YES];
[newModel setValue: accessibleFieldValue forKey:#"accessible"];
I've checked and there are no nil values entered in the sqlite database.
What should I do?
It works fine with the new literals:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"done = %#",#NO];
NSNumber *accessibleFieldValue = [NSNumber numberWithBool:YES];
[newModel setValue:accessibleValue forKey:#"accessible"];
accessibleFieldValue or accessibleValue? If you're sure this snippet of code is right, that's where you did wrong.
And b.t.w, you can set value simply like:
newModel.accessible = [NSNumber numberWithBool:YES];
I ended up going to the database in sqlite database browser and changing the type for the field value to Numeric. For some reason core data entered the data as an incompatible data type.....don't really know why, but I have a feeling this might be an Xcode bug. As I said, it works now after I changed the field type. I don't think I will be using boolean values in core data any time soon.....at least not until I understand why this was a problem.

Use NSPredicate to filter object in core data

I have three entities A, B, C.
The relationship between them is: A <-->>B, B<-->C.
A has a attribute called 'type'.
A and B relationship is a2b, B and C relationship is b2c. c_array is list of C object.
What I am trying to do is using NSPredicate to filter A by C and A's attribute 'type'.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"A" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSMutableArray *parr = [NSMutableArray array];
for (C *c in c_array) {
[parr addObject:[NSPredicate predicateWithFormat:#"ANY a2b.b2c = %#", c]];
}
NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:[NSCompoundPredicate orPredicateWithSubpredicates:parr], [NSPredicate predicateWithFormat:#"type = %i", 0], nil]];
[fetchRequest setPredicate:predicate];
But what I get is not I expected. So I tried other as well.
predicate = [NSPredicate predicateWithFormat:#"type=%i AND (0!=SUBQUERY(a2b,$a2b,$a2b.b2c IN %#).#count)", 0, c_array];
Unexpected result happened again! Can somebody help me out? T T
Sounds like you want to do it the other way around. You already have the C's, and based on the relationships you've described, your C class would have a B property, and your B class would have an A property. So assuming you've used c2b and b2a something like this should work:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"c2b.b2a.type == %#",[NSNumber numberWithInt:0]];
NSArray *result = [c_array filteredArrayUsingPredicate:predicate];
Also I notice you're comparing the type attribute of A to an int in your predicate. Just looking for type==%i where i is 0 will return all objects that have no value in type. So either compare type to an NSNumber object or type.intValue to the int.

Number of elements in NSArray where (....)

I am used to working in C# using the linq extensions (list.select(...).where(...) ext), and I was wondering if there was some way of doing the same sort of thing in Objective-C. This would save me from building a number of rather complicated queries using Core Data, which is great for some things, but perhaps not the best for complex queries (or maybe I'm just uninformed).
Is there some kind of equivalent for linq in Objective-C/Core Data?
EDIT: More specifically, I would like to count the number of elements that fit some criteria. Say my model has a field called date. I am trying to select the distinct dates, and then calculate how many of each date there are. In SQL this would be like a group by, and a COUNT aggregate.
Your question goes from very general ("linq equivalent?") to very specific (computing count by date). I'll just answer your specific question.
Unfortunately, NSArray doesn't have a built-in map or select method, but it does offer NSCountedSet, which will compute what you want:
NSCountedSet *dateSet = [NSCountedSet set];
for (id thing in array) {
[dateSet addObject:[thing date]];
}
for (NSDate *date in dateSet) {
NSLog(#"There are %d instances of date %#", [dateSet countForObject:date], date);
}
Change predicate , and "Date" keys with your props
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"child" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setReturnsDistinctResults:YES];
[fetchRequest setPropertiesToFetch:[NSArray arrayWithObject:#"Date"]];
NSPredicate *predicate =[NSPredicate predicateWithFormat:#"(start <= %# ) and (completion < 100)",sda ];
[fetchRequest setPredicate:predicate];
int c = [self.managedObjectContext countForFetchRequest:fetchRequest error:nil];
Here was something posted with comes close
filtering NSArray into a new NSArray in objective-c
Anyway AFAIK you don't have some sort of linq in Objective-C but you have. Arrays and Blocks. And Blocks are functions. So you can really filter on anything in there.
Of course, Cora Data has many functions to make complex queries:
In example to get sum of elements, you have two major ways:
first - get your data to NSSet or NSArray and use #sum operator:
//assume that `childs` are NSArray of your child entities and ammount is attribute to sum, and has attributes start (date) and completion (integer)
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"child" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *predicate =[NSPredicate predicateWithFormat:#"(start <= %# ) and (completion < 100)", dzis];
[fetchRequest setPredicate:predicate];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:#"Root"];
NSError *error = nil;
if ([afetchedResultsController performFetch:&error]) {
NSArray *childs = afetchedResultsController.fetchedObjects;
NSNumber *sum=[childs valueForKeyPath:"#sum.ammount"];
}
second is using specific fetch for specific value with added NSExpressionDescription with a sum. This way is harder but better for larger db's
suppose if you have an array of your model objects, you could that with the following statement,
NSArray *distintDatesArray = [array valueForKeyPath:#"#distinctUnionOfObjects.date"];
for ( NSDate *date in distintDatesArray)
{
NSLog (#"Date :%# ,count : %d",date,[[array filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"date = %#",date]] count]);
}
This will have same effect as the group by query.