Predicate search not working (core data) - objective-c

When inserting in the "FilterProperty" entity, I use the following code in a category "FilterProperty+Manage.h"
+(FilterProperty *)insertFilterPropertyWithName:(NSString *)filterPropertyName forManagedObjectContext:(NSManagedObjectContext *)managedObjectContext forFriendlyName:(NSString *)friendlyName
forDefaultValue:(NSNumber *)defaultValue forMinValue:(NSNumber *)minValue forMaxValue:(NSNumber *)maxValue forType:(NSNumber *)type forBelongsToFilter:(Filter *)filter
{
FilterProperty *fp = nil;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"FilterProperty" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name = %# AND belongsToFilter.name = %#", filterPropertyName, filter.name];
[fetchRequest setPredicate:predicate];
NSError *error = nil;
NSArray *fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil)
{
return nil;
}
if (fetchedObjects != nil && fetchedObjects.count > 0)
{
fp = fetchedObjects.firstObject;
}
else if(fetchedObjects != nil && fetchedObjects.count == 0)
{
fp = [NSEntityDescription insertNewObjectForEntityForName:#"FilterProperty" inManagedObjectContext:managedObjectContext];
fp.name = filterPropertyName;
fp.friendlyName = friendlyName;
fp.defaultValue = defaultValue;
fp.minValue = minValue;
fp.maxValue = maxValue;
fp.belongsToFilter = filter;
fp.type = type;
}
return fp;
}
No while searching, I do the following:
+(NSArray *)getAllFilterPropertiesForFilter:(Filter *)filter forManagedObjectContext (NSManagedObjectContext *)managedObjectContext
{
NSArray *set = nil;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"FilterProperty" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"belongsToFilter.name = %#", filter.name];
[fetchRequest setPredicate:predicate];
NSError *error = nil;
NSArray *fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
return nil;
}
if(fetchedObjects != nil)
{
set = fetchedObjects;
}
return set;
}
The above function when called for any given filter is returning an array with zero objects. I am not able to get why. Any help would be appreciated! Thanks.

You try out this code for searching:-
+(NSArray *)getAllFilterPropertiesForFilter:(Filter *)filter forManagedObjectContext (NSManagedObjectContext *)managedObjectContext
{
NSArray *set = nil;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"FilterProperty" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"belongsToFilter.name == %#", filter.name];
[fetchRequest setPredicate:predicate];
NSError *error = nil;
NSArray *fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
return nil;
}
if(fetchedObjects != nil)
{
set = fetchedObjects;
}
return set;
}

I think in your insertFilterPropertyWithName method you are not saving the new data. If I am correct, try this code after your if-else block:
NSError *error;
if (![managedObjectContext save:&error])
{
//could not save
}
Hope this could resolve your problem.

In that below if condition you need to save in managedobjectcontext.
else if(fetchedObjects != nil && fetchedObjects.count == 0)
{
fp = [NSEntityDescription insertNewObjectForEntityForName:#"FilterProperty" inManagedObjectContext:managedObjectContext];
fp.name = filterPropertyName;
fp.friendlyName = friendlyName;
fp.defaultValue = defaultValue;
fp.minValue = minValue;
fp.maxValue = maxValue;
fp.belongsToFilter = filter;
fp.type = type;
NSError *err = nil;
[managedObjectContext save:&err];
if (errorInWrite != nil) {
//Problem while saving
}
}
Use like instead of "=" Hope it will be useful.
+(NSArray *)getAllFilterPropertiesForFilter:(Filter *)filter forManagedObjectContext (NSManagedObjectContext *)managedObjectContext
{
NSArray *set = nil;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"FilterProperty" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"belongsToFilter.name like %#", filter.name];
[fetchRequest setPredicate:predicate];
NSError *error = nil;
NSArray *fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
return nil;
}
if(fetchedObjects != nil)
{
set = fetchedObjects;
}
return set;
}

Related

Saving data in background thread doesn't work

I am trying to save my data in CoreData in background thread, but it crash or it doesnt work, any idea where am I doing the mistake?
When I try with main thread it works correctly, I tried to google to find some information in background thread, I couldn't find some useful article about it.
any help appreciate.
Thanks
This is the objective -c code, what I tried
-(void)insertNameAndSurnameInDataBase:(NSString *)name surname:(NSString *)surname numbers:(NSArray *)numbers labels:(NSArray *)labels{
NSManagedObjectContext *backgroundMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[backgroundMOC performBlock:^{
NSError *error;
NameAndSurname *nameAndSurname = [NSEntityDescription insertNewObjectForEntityForName:#"NameAndSurname" inManagedObjectContext:backgroundMOC];
NSString *nSurname = [NSString stringWithFormat:#"%# %#",name,surname];
nameAndSurname.nameSurname = nSurname;
if ([backgroundMOC save:&error]) {
}
else{
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"NameAndSurname"
inManagedObjectContext:backgroundMOC];
// predicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"nameSurname =[c] %#", nSurname];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:predicate];
[fetchRequest setReturnsObjectsAsFaults:NO];
NSArray *fetchedObjects = [backgroundMOC executeFetchRequest:fetchRequest error:&error];
if([fetchedObjects count] > 0){
[numbers enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
id obj2 = [labels objectAtIndex:idx];
obj = [obj stringByReplacingOccurrencesOfString:#" " withString:#""];
ContactNumber *phoneNumber = [NSEntityDescription insertNewObjectForEntityForName:#"ContactNumber" inManagedObjectContext:backgroundMOC];
phoneNumber.number = obj;
phoneNumber.label = obj2;
phoneNumber.nameAndSurname = fetchedObjects[0];
NSError *error;
if ([backgroundMOC save:&error]) {
}
else{
}
}];
}
}];
}

Unit testing with core data in objective c

My coredata methods are here. How to write unit test case to check this.
Method to save to coredata
- (void)saveUserDetails:(Model *)userDetail {
if(userDetail != nil) {
UserEntity *user = [NSEntityDescription insertNewObjectForEntityForName:#“EntityName” inManagedObjectContext:[self sharedContext]];
NSArray *fetchArray = [self fetchUserWithUsername:userDetail.username];
if ([fetchArray count] == 0) {
user.username = userDetail.username;
[self saveContext];
}
}
}
Method to fetch from coredata
- (NSArray *)fetchUserWithUsername:(NSString *)username {
if (username != nil) {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *userEntity = [NSEntityDescription entityForName:#“EntityName” inManagedObjectContext:[self sharedContext]];
[fetchRequest setEntity:userEntity];
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"username = %#", username];
NSError *error;
NSArray *fetchedObjects = [[self sharedContext] executeFetchRequest:fetchRequest error:&error];
return fetchedObjects;
}
return nil;
}
Create an in-memory store and inject this into your object.
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"MyResource" withExtension:#"momd"];
NSManagedObjectModel *mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
XCTAssertTrue([psc addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:nil options:nil error:NULL] ? YES : NO, #"Should be able to add in-memory store");
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
context.persistentStoreCoordinator = psc;

Recipes to update database in Core Data

I have a method for adding stamp to the card, from QR code reader to web service
my question is,
Here is my code:
- (void)addStamp
{
NSString *url = [_URL stringByAppendingString:#"add-stamp"];
NSString *post = [NSString stringWithFormat:#"userId=%#&code=%#", self.userId, self.code ];
post = [post stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSData *postData = [NSData dataWithBytes:[post UTF8String]
length:[post lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL
URLWithString:url] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:600];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:postData];
}
Rightnow I want to update my DB with new method -> if the code is repeated add stamp, if not create add a new card:
-(void)addStampInDB:(int)cardId
{
NSManagedObjectContext* managedObjectContext = [(AppDelegate*) [[UIApplication
sharedApplication] delegate] managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Card"
inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"remote_id = %d", cardId];
[fetchRequest setPredicate:predicate];
[managedObjectContext lock];
NSError *error;
NSArray *fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest
error:&error];
[managedObjectContext unlock];
Card *d = nil;
if([fetchedObjects count] > 0 ){
d = [fetchedObjects objectAtIndex:0];
cardId++;
} else{
d = [NSEntityDescription insertNewObjectForEntityForName:#"Card"
inManagedObjectContext:managedObjectContext];
}
NSArray *test;
for(NSDictionary *stamp in test)
{
d.remote_id = [NSNumber numberWithInt:[[stamp objectForKey:#"id"] intValue]];
d.stampNumber = [NSNumber numberWithInt:[[stamp objectForKey:#"stampNumber"] intValue]];
d.createdAt = [NSDate dateWithTimeIntervalSince1970:[[stamp objectForKey:#"createdAt"]
intValue]];
[managedObjectContext lock];
NSError *error;
if (![managedObjectContext save:&error])
{
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
NSLog(#"Failed to save to data store: %#", [error localizedDescription]);
NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
if(detailedErrors != nil && [detailedErrors count] > 0) {
for(NSError* detailedError in detailedErrors) {
NSLog(#" DetailedError: %#", [detailedError userInfo]);
}
} else {
NSLog(#" %#", [error userInfo]);
}
}
[managedObjectContext unlock];
}
}
I don't know if I'm in a right way or not and also how I can test my method?
I'm not very sure about your question but I'll try to give some hints.
First
Card *d = nil;
if([fetchedObjects count] > 0 ){
d = [fetchedObjects objectAtIndex:0];
cardId++;
} else{
d = [NSEntityDescription insertNewObjectForEntityForName:#"Card"
inManagedObjectContext:managedObjectContext];
}
Here you have found an existing card, you use it, else you create a new. Question: what about cardId? Where is it used?
Second
for(NSDictionary *stamp in test)
{
d.remote_id = [NSNumber numberWithInt:[[stamp objectForKey:#"id"] intValue]];
d.stampNumber = [NSNumber numberWithInt:[[stamp objectForKey:#"stampNumber"] intValue]];
d.createdAt = [NSDate dateWithTimeIntervalSince1970:[[stamp objectForKey:#"createdAt"]
intValue]];
// other code here
}
If you loop test, you overwrite the value of your card d each time. Is it right?
Third
for(NSDictionary *stamp in test)
{
// other code here
}
// save here
Move the save out of the for loop. This boost performances in your app. It is not necessary to save each time in your loop. Do it at the end only.
Hope that helps.
P.S. If you want to know something else let me know.

NSFetchedResultsController for new object

I have UITableViewController with static editable cells. In my UITableViewController I make CoreData object, like this:
- (User*)user {
if (_user == nil) {
_user = [NSEntityDescription insertNewObjectForEntityForName:TABLE_USER inManagedObjectContext:self.managedObjectContext];
NSError* error;
[self.managedObjectContext save:&error];
if (error != nil) {
abort();
}
}
return _user;
}
I want to get the object in NSFetchedResultsController that would display its fields in a table, and then save the object.
I'm trying to do:
- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:TABLE_USER_PROFILE inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"lastName" ascending:NO];
NSArray *sortDescriptors = #[sortDescriptor];
NSPredicate* pred = [NSPredicate predicateWithFormat:#"%# = %#", TABLE_USER, self.user];
[fetchRequest setPredicate:pred];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:TABLE_USER];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error]) {
abort();
}
return _fetchedResultsController;
}
But it didn't work. I get empty fetchedResultsController.
If self.user is a NSManagedObject and you query against a User entity you could try to edit your predicate like the following:
NSPredicate* pred = [NSPredicate predicateWithFormat:#"self == %#", self.user];
Hope that helps.
P.S. If my answer doesn't work try to provide some other details (see my comment)

executeFetchRequest:error A fetch request must have an entity

I am getting error in the search part. when i enter the song name i should get the lyrics there but getting an error says 'executeFetchRequest:error: A fetch request must have an entity.' i used the following code
-(void)findLyrics
{
LyricsAppDelegate *appDelegate = [[UIApplication sharedApplication]
delegate];
NSManagedObjectContext *managedObjectContext = [appDelegate managedObjectContext];
NSEntityDescription *entityDesc = [NSEntityDescription
entityForName:#"Lyrics"inManagedObjectContext:managedObjectContext];
NSManagedObject *LyricsObjectEnglish;
LyricsObjectEnglish = [NSEntityDescription insertNewObjectForEntityForName:#"English_Songs"
inManagedObjectContext:managedObjectContext];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:entityDesc];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(MovieSongName = %#)",song_name.text];
[request setPredicate:pred];
NSManagedObject *matches = nil;
NSError *error;
NSArray *objects = [managedObjectContext executeFetchRequest:request error:&error];
if ([objects count] == 0)
{
//status.text = #"No matches";
} else {
matches = [objects objectAtIndex:0];
song_lyrics.text = [matches valueForKey:#"SongLyrics"];
song_name.text = [matches valueForKey:#"MovieSongName"];
// status.text = [NSString stringWithFormat:#"%d matches found", [objects count]];
}
[request release];
}
Any body please help..