Having trouble copying data to a mutable array - iphone

I keep getting the error "Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[MainViewController minimalFormInContext:]: unrecognized selector sent to class"
from this line of code:
NSLog(#"Accessing specific mine entities");
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Mine" inManagedObjectContext:managedObjectContext];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
NSError *error = nil;
[request setEntity:entity];
NSPredicate *predicate;
NSPredicate *metalFilter;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *region = [defaults stringForKey:#"mineArray"];
if([region isEqualToString:#"Butte & Plumas"])
{
predicate = [NSPredicate predicateWithFormat:#"(county Contains %#) OR (county Contains %#)",#"Butte",#"Plumas"];
}
else if([region isEqualToString:#"Sutter, Yuba, & Sierra"])
{
predicate = [NSPredicate predicateWithFormat:#"(county Contains %#) OR (county Contains %#) OR (county Contains %#)",#"Sutter",#"Yuba",#"Sierra"];
}
else if([region isEqualToString:#"Nevada & Placer"])
{
predicate = [NSPredicate predicateWithFormat:#"(county Contains %#) OR (county Contains %#)",#"Nevada",#"Placer"];
}
else if([region isEqualToString:#"Sacramento & El Dorado"])
{
predicate = [NSPredicate predicateWithFormat:#"(county Contains %#) OR (county Contains %#)",#"Sacramento",#"El Dorado"];
}
else if([region isEqualToString:#"San Joaquin, Amador, & Calaveras"])
{
predicate = [NSPredicate predicateWithFormat:#"(county Contains %#) OR (county Contains %#) OR (county Contains%#)",#"San Joaquin",#"Amador", #"Calaveras"];
}
else if([region isEqualToString:#"Tuolumne & Stanislaus"])
{
predicate = [NSPredicate predicateWithFormat:#"(county Contains %#) OR (county Contains %#)",#"Tuolumne",#"Stanislaus"];
}
else if([region isEqualToString:#"Merced, Mariposa, & Madera"])
{
predicate = [NSPredicate predicateWithFormat:#"(county Contains %#) OR (county Contains %#) OR (county Contains %#)",#"Merced",#"Mariposa",#"Madera"];
}
[request setPredicate:predicate];
mArray = [[NSMutableArray alloc] init];
mArray = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
using debugger, I have narrowed down the error as occurring in:
mArray = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
How do I fix this?

It's likely that it's a retain/release bug. Do "Build and Analyze" in XCode, and improve your code to remove all of the warnings.
Here are things I noticed:
mArray = [[NSMutableArray alloc] init];
mArray = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
These two lines are very bad. What's your mArray? Does m stands for member, or mutable? If it's a member variable, you shouldn't just assign a new array to that as in
// mArray points to an array at this time, say X
mArray = [[NSMutableArray alloc] init];
// at this point, mArray points to an array Y created by alloc init. X is lost!
Moreover, if you further assign a mutableCopy as you did,
mArray = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
// at this point, mArray points to an array Z created by mutableCopy. Y is lost, too!
Note that in Objective-C, the variables you see on the source code is just a pointer, not the object itself. If you assign something to a variable, it doesn't make the object perform the assign operation, but it just changes the pointer to point to something different.
The fact that you have these lines suggests you have similar things in various other places; any of it can eventually lead to the bug you're encountering. So you need to deal with them one by one. Good luck!
Another point: when you prepare the variable predicate, the chain of if clauses leaves predicate undefined if region matches none of the choices you listed. This is very dangerous, because in Objective-C, the line
NSPredicate* predicate;
does not initialize predicate to be nil. So it's possible that
[request setPredicate:predicate];
will set a garbage to the predicate of requrest. You should change it to
NSPredicate* predicate=nil;

Related

NSPredicate limit results

I am trying to limit array of objects getting with [NSArray filteredArrayUsingPredicate] for better performance.
My Code:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.Name contains[c] %#", searchText];
NSArray *filteredArray = [self.dataArray filteredArrayUsingPredicate:predicate];
My dataArray contains about 30.000 objects and I want to limit result array 50. (I need some break statement after 50 match found.) How can I achieve this?
Use simple for-in loop, NSMutableArray builder and -[NSPredicate evaluateWithObject:] method.
NSMutableArray *builder = [NSMutableArray arrayWithCapacity:50];
for (id object in array) {
if ([predicate evaluateWithObject:object]) {
[builder addObject:object];
if (builder.count >= 50) break;
}
}
I noticed you tagged the question by Core Data. If you can use NSFetchRequest, then just set its fetchLimit to 50.
How about this?
myArray = [originalArray filteredArrayUsingPredicate:myPredicate];
if ([myArray count] > resultLimit) {
myArray = [myArray subarrayWithRange:NSMakeRange(0, resultLimit)];
}

How to with create a compoundPredicate with both "OR" and "AND"

I have the following 3 categories fetched, but want to add a "AND" predicate to narrow the results, where the "mark" is on.
NSMutableArray *questionNumberArray=[[NSMutableArray alloc] init];
// Fetch questions
NSManagedObjectContext *context = self.document.managedObjectContext;
NSFetchRequest *fetchRequest =
[[NSFetchRequest alloc] initWithEntityName:#"Questions"];
//building the predicate with selected category
NSMutableArray *parr = [NSMutableArray array];
if ([cat0str length]){
[parr addObject:[NSPredicate predicateWithFormat:#"question.category CONTAINS[c] %#",cat0str]];
}
if ([cat1str length]){
[parr addObject:[NSPredicate predicateWithFormat:#"question.category CONTAINS[c] %#",cat1str]];
}
if ([cat2str length]){
[parr addObject:[NSPredicate predicateWithFormat:#"question.category CONTAINS[c] %#",cat2str]];
}
NSPredicate *compoundPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:parr];
[fetchRequest setPredicate:compoundPredicate];
NSPredicate *markPredicate =[NSPredicate predicateWithFormat:#"question.mark == 1"];
}
//I'd like to do something like that:
NSPredicate *finalPredicate = [compoundPredicate && markPredicate];
[fetchRequest setPredicate:finalPredicate];
Is this what you are looking for?
NSPredicate *finalPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:
[NSArray arrayWithObjects:compoundPredicate, markPredicate, nil]];
or, using the "modern Objective-C" syntax for container literals:
NSPredicate *finalPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:
#[compoundPredicate, markPredicate]];

Core Data: does a fetch have to make a trip to persistent store?

Say I do this:
NSManagedObjectContext *context = #a managed object context";
NSString *entityName = #an entity name#;
NSFetchRequest *requestForAll = [NSFetchRequest requestWithEntityName:entityName];
NSArray *allObj = [context executeFetchRequest:requestForAll];
for (NSString *name in allNamesArray){
NSFetchRequest *requestForOne = [NSFetchRequest requestWithEntityName:entityName];
requestForOne.predicate = [NSPredicate predicateWithFormat:#"name == %#",name];
NSArray *ObjsWithName = [context executeFetchRequest:requestForOne];
#do some work with the obj#
}
Does the fetch in the loop incur a trip to the persistent store every time? Or those fetches will only be performed in coredata's row cache?
EDIT
I've written a fragment of testing code :
You need to create a core data entity named "Person" and it should have an attribute named "name", which is of type string.
use this code to populate some data:
self.array = #[#"alkjsdfkllaksjdf",#"asldjflkajdklsfjlk;aj",#"aflakjsdl;kfjalksdjfklajkldhkl;aj",#"aljdfkljalksdjfl;j" ,#"flajdl;kfjaklsdjflk;j",#"akldsjfklajdslkf",#"alkdjfkljaklsdjflkaj",#"alsdjflkajsdflj",#"adlkfjlkajsdfkljkla",#"alkdjfklajslkdfj"];
NSString *firstRunKey = #"oh its first run!";
NSString *firstRun = [[NSUserDefaults standardUserDefaults] objectForKey:firstRunKey];
if (!firstRun) {
for (NSString *name in self.array) {
Person *p = [NSEntityDescription insertNewObjectForEntityForName:#"Person" inManagedObjectContext:self.managedObjectContext];
p.name = name;
}
}
[self.managedObjectContext save];
[[NSUserDefaults standardUserDefaults] setObject:firstRunKey forKey:firstRunKey];
[[NSUserDefaults standardUserDefaults] synchronize];
profile this two methods and you'll find usingCoreData costs much more time than usingFilterArray!
static int caseCount = 1000;
-(void)usingCoreData
{
NSLog(#"core data");
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:#"Person"];
NSArray *allPersons = [self.managedObjectContext executeFetchRequest:request error:nil];
for (int i = 0; i < caseCount; i++){
for (NSString *name in self.array) {
request.predicate = [NSPredicate predicateWithFormat:#"name == %#",name];
NSArray *result = [self.managedObjectContext executeFetchRequest:request error:nil];
}
}
}
-(void)usingFilterArray
{
NSLog(#"filter array");
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:#"Person"];
NSArray *allPersons = [self.managedObjectContext executeFetchRequest:request error:nil];
for (int i = 0; i < caseCount; i++){
for (NSString *name in self.array) {
NSArray *array = [allPersons filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"name == %#",name]];
}
}
}
Guess I need to answer my question myself.
I tested it and found, every time a fetch executed, core data will translate your NSFetchRequest into SQL command and invoke a data base query,the query result is firstly NSManagedObjectIDs, caching is applied to get the NSManagedObject from a NSManagedObjectID.
In conclusion, it caches object, but doesn't cache query result.
That means you execute the same NSFetchRequest for 10 times, it will query your persistent store for 10 times, event though you will get 10 times the same result. So in such situation, filtering array in memory will perform better than fetching.
The fetch will come from the specified cache when available.
EDIT:
Here's a link to a great tutorial that shows how to set up a NSFetchedResultsController that uses a cache.
http://www.raywenderlich.com/?p=999

object and NSPredicate

In my application i have a large table of around 12000 entries. I am displaying it on tableview. But the search bar is too slow while doing dynamic search. I have read that NSPredicate method is more permorfant then NSRange.
This is my old the code:
[self.filteredListContent removeAllObjects];
listContent = [[NSArray alloc] initWithArray:[dbAccess getAllBooks]];
for (Book *book in listContent)
{
NSRange range = [book.textBook rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (range.location != NSNotFound)
{
[self.filteredListContent addObject:book];
}
}
My new code:
[self.filteredListContent removeAllObjects];
listContent = [[NSArray alloc] initWithArray:[dbAccess getAllBooks]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF like[c] %#",searchText];
[self.filteredListContent addObject:[listContent filteredArrayUsingPredicate:predicate]];
When i try to execute this code i received this error: "Can't do regex matching on object .'"
I would do something more like...
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%k like[c] %#",propertyIAmLookingFor,searchText];
Is your book class a string? If not then you cant use SELF like. You need to substitute the name of the property you are comparing.

NSCompoundPredicate fails to match

I'm building a NSPredicate using the code below for an iPhone app. The logging shows the prediate to be: location CONTAINS "head" AND shape CONTAINS "oval" AND texture CONTAINS "bumpy" AND colour CONTAINS "red"
I get no results. If I limit the predicate to a single item it will work, more than 1 fails.
Can anyone tell me why?
Many thanks
NSMutableArray *subPredicates = [[NSMutableArray alloc] init];
for (Ditem in self.tableDataSource) {
NSString *Title = [Ditem valueForKey:#"Title"];
NSString *Value = [Ditem valueForKey:#"Value"];
if([[Value lowercaseString] isEqualToString: #"all"]){
Value = #"";
}
else{
NSPredicate *p = [NSComparisonPredicate predicateWithLeftExpression:[NSExpression expressionForKeyPath:[Title lowercaseString]] rightExpression:[NSExpression expressionForConstantValue:[Value lowercaseString]] modifier:NSDirectPredicateModifier type:NSContainsPredicateOperatorType options:0];
[subPredicates addObject:p];
}
}
NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:subPredicates];
NSLog(#"predicate: %#", predicate);[self.fetchedResultsController.fetchRequest setPredicate:predicate];
Your predicate is requiring that all of the values in your filterable objects be strings. Is that correct?
Also, I would simplify your subpredicate creation to:
NSPredicate * p = [NSPredicate predicateWithFormat:#"%K CONTAINS %#", [Title lowercaseString], [Value lowercaseString]];