Error saving data in Core Data (IOS) - ios

My program receives the JSON data from the Web service. Next, the program stores the data in the database using Core Data. If I call the save data after adding each entry, everything works, but very slowly. Keeping 200 entries takes more than one minute.
If I execute saving only once at the end – the program throw exception.
- (void) onLoadMessages:(NSObject*)object {
NSArray *messages = (NSArray*)object;
if (messages==nil) {
[self onError:#"Message array is null"];
return;
}
NSDate *date = [NSDate date];
long now = [date timeIntervalSince1970];
Boolean update = false;
for(int i=0; i<messages.count; i++) {
NSDictionary *m = messages[i];
Message *msg = [[Message alloc]initWithDictionary:m];
if ([self UpdateMessage:msg UpdateTime:now])
update = true;
}
if (update) {
NSError *error = nil;
// Error throw here
if (![self.managedObjectContext save:&error])
[self onError2:error];
}
}
- (Boolean) UpdateMessage:(Message*) msg UpdateTime:(long)now {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Messages" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSString *s = [NSString stringWithFormat:#"%ld", msg.id];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(id=%#)", s];
[fetchRequest setPredicate:pred];
NSError *error;
NSArray *object = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
Boolean result = false;
if (object==nil)
[self onError2:error];
else {
NSManagedObject *m;
if ([object count]==0) {
// Insert new message
m = [NSEntityDescription insertNewObjectForEntityForName:#"Messages"
inManagedObjectContext:self.managedObjectContext];
[m setValue:[NSNumber numberWithLong:msg.id] forKey:#"id"];
[m setValue:[NSNumber numberWithLong:msg.agancy.id] forKey:#"agancy"];
[m setValue:msg.header forKey:#"header"];
[m setValue:msg.keywords forKey:#"keywords"];
[m setValue:[NSNumber numberWithLong:msg.indate] forKey:#"indate"];
[m setValue:[NSNumber numberWithLong:now] forKey:#"updated"];
result = true;
} else {
// Update message
m = [object objectAtIndex:0];
[m setValue:[NSNumber numberWithLong:now] forKey:#"updated"];
}
// Save the context.
// Too long execution
/*NSError *error = nil;
if (![self.managedObjectContext save:&error])
[self onError2:error];*/
}
return result;
}
Help correct the behavior of the program.
With respect,
Alexander.
P.S.
Execution takes place in the main thread.
Field "Id" for table "Messages" indexed.

I solve the problem by adding privateObjectContext!
_privateObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
And replace managedObjectContext on privateObjectContext when updating/inserting data/

Related

Force use of an entity already create with NSUserDefaults

I'm trying to get to select or button one or two button the application will create an entity related to that neighborhood and thus show the following screens according to the selection. To avoid the creation of entities each time decided to use the NSUserDefaults and implementation is this:
- (void)carregarEntidadeLojaComId:(NSString *)identificadorLoja keyNSUserDefault:(NSString *)key {
if (![[NSUserDefaults standardUserDefaults] objectForKey:key]) {
NSManagedObjectContext *contexto = [self managedObjectContext];
NSArray *arrayLojas = [Utils carregarArrayPlist:identificadorLoja];
NSArray *atributosComuns = #[#"titulo", #"subtitulo", #"telefone", #"endereco"];
for (NSDictionary *dicionario in arrayLojas) {
loja = [NSEntityDescription insertNewObjectForEntityForName:#"Loja" inManagedObjectContext:contexto];
categoria = [NSEntityDescription insertNewObjectForEntityForName:#"Categoria" inManagedObjectContext:contexto];
quadra = [NSEntityDescription insertNewObjectForEntityForName:#"Quadra" inManagedObjectContext:contexto];
//Loop para atributos comuns
for (NSString *atributo in atributosComuns) {
[loja setValue:[dicionario objectForKey:atributo] forKey:atributo];
}
[categoria setValue:[dicionario objectForKey:#"categoria"] forKey:#"nome"];
[loja setValue:categoria forKey:#"categoria"];
[quadra setValue:[dicionario objectForKey:#"quadra"] forKey:#"nome"];
[loja setValue:quadra forKey:#"quadra"];
}
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:key];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
Turning the first time, the application identifies that there is no key and enters the if statement, therefore, create the entity. Already from the second time you use the application it will not enter the if statement, but he can not use the entity that has been created and so the screens that depend on them are not fulfilled. My question is how to force the application to use the entity that has been created the first time that the user clicked the application.
Is there really NSUserDefaults needed?
Why not just query entity from CoreData itself, like this:
- (void)carregarEntidadeLojaComId:(NSString *)identificadorLoja keyNSUserDefault:(NSString *)key {
NSManagedObjectContext *contexto = [self managedObjectContext];
NSFetchRequest *request = [NSFetchRequest new];
request.entity = [NSEntityDescription entityForName:#"Loja"
inManagedObjectContext:contexto];
request.predicate = [NSPredicate predicateWithFormat:#"identificador = %#", identificadorLoja];
NSError *error = nil;
NSArray *fetchedObjects = [contexto executeFetchRequest:request error:&error];
NSArray *lojas = nil;
if ((error == nil) && [fetchedObjects count] > 0)
lojas = fetchedObjects;
if (!lojas) {
NSArray *arrayLojas = [Utils carregarArrayPlist:identificadorLoja];
NSArray *atributosComuns = #[#"titulo", #"subtitulo", #"telefone", #"endereco"];
for (NSDictionary *dicionario in arrayLojas) {
loja = [NSEntityDescription insertNewObjectForEntityForName:#"Loja" inManagedObjectContext:contexto];
//Loop para atributos comuns
for (NSString *atributo in atributosComuns) {
[loja setValue:[dicionario objectForKey:atributo] forKey:atributo];
}
[loja setValue:[self categoriaWithNome:[dicionario objectForKey:#"categoria"]
inContexto:contexto]
forKey:#"categoria"];
[loja setValue:[self quadraWithNome:[dicionario objectForKey:#"quadra"]
inContexto:contexto]
forKey:#"quadra"];
[loja setValue:identificadorLoja
forKey:#"identificador"];
}
} else {
// do what you want with loja's, previously stored in CoreData
for (NSManagedObject *entity in lojas)
...
}
}
- (NSManagedObject *) categoriaWithNome:(NSObject *)nome inContexto:(NSManagedObjectContext *)contexto {
NSManagedObject *categoria = [NSEntityDescription insertNewObjectForEntityForName:#"Categoria" inManagedObjectContext:contexto];
[categoria setValue:nome forKey:#"nome"];
return categoria;
}
- (NSManagedObject *) quadraWithNome:(NSObject *)nome inContexto:(NSManagedObjectContext *)contexto {
NSManagedObject *quadra = [NSEntityDescription insertNewObjectForEntityForName:#"Quadra" inManagedObjectContext:contexto];
[quadra setValue:nome forKey:#"nome"];
return quadra;
}
Upd.
Added predicate to request and removed limit, as it seems like you have multiple loja's for each identificadorLoja.

Core Data not saving an incremented integer

I'm making a SpriteKit game and I need to save the player's score using Core Data. I have a property with int value that starts off as being set to "5" and increment it x amount of times. I save it then transition to a different scene and fetch it. It shows up un-incremented with the initial value of "5".
I'm new to Core Data so forgive me if this is a stupid question, but how can I get Core Data to take the incrementation in to account? Or Is information being lost when I reference the property and how can I prevent this?
self.score = 5;
self.score++
and then save by calling this method.
AppDelegate.m
-(void) createObject {
Score *scoreEntity = (Score *)[NSEntityDescription
insertNewObjectForEntityForName:#"Score"
inManagedObjectContext:self.managedObjectContext];
SpaceshipScene *spaceshipSceneReference = [[SpaceshipScene alloc] init];
id points = [NSNumber numberWithInteger: spaceshipSceneReference.score];
scoreEntity.points = points;
scoreEntity.playerName = #"Joe";
NSError *error = nil;
// Saves the managedObjectContext
if (! [[self managedObjectContext] save:&error] ) {
NSLog(#"An error! %#", error);
}
}
This is how I call it.
SpaceshipScene.m
AppDelegate *appDelegateReference = [[AppDelegate alloc] init];
[appDelegateReference createObject];
I then fetch it in another class/scene using this method
AppDelegate.m
-(void)fetchObject {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Score"inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
// Sort fetched data
NSSortDescriptor *sortByPoints = [[NSSortDescriptor alloc] initWithKey:#"points" ascending:NO];
// Put them in an array
NSArray *sortDescriptor = [[NSArray alloc] initWithObjects:sortByPoints, nil];
// Pass the array to the fetch request
[fetchRequest setSortDescriptors:sortDescriptor];
NSError *error = nil;
NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
NSLog(#"Problem %#", error);
}
for (Score *s in fetchedObjects) {
NSLog(#" %# %d",s.playerName, [s.points integerValue]);
}
}
This is how I call it in the final scene/class
AppDelegate *appDelegateReference = [[AppDelegate alloc] init];
[appDelegateReference fetchObject];
Hope this will work, after fetching your Score entity , simply assign new values in it don't use insert object for update any value.
[scoreEntity setPoints:[NSNumber numberWithInteger: spaceshipSceneReference.score]];
[scoreEntity setPlayerName:#"Joe"];
then Save the values:
NSError *error = nil;
// Saves the managedObjectContext
if (! [[self managedObjectContext] save:&error] ) {
NSLog(#"An error! %#", error);
}

Unrecognised selector sent to instance when trying to insert in CoreData

I am trying to save some data to CoreData but i get the error:
Restaurant Manager[5971:60b] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ProdusComandat setIdProdus:]: unrecognized selector sent to instance 0x90b8270'
Can someone tell me why?
SessionController* sessionController = [[SessionController alloc]init];
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"ComenziActive"];// baza de date
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"numeClient == %#",sessionController.getSessionUsername]];
NSError *err;
NSUInteger count = [self.managedObjectContext countForFetchRequest:fetchRequest error:&err];
NSArray *listaElementeBD = [[NSArray alloc]init];
if(count <= 0)
{
NSEntityDescription *entitydesc;
entitydesc = [NSEntityDescription entityForName:#"ComenziActive" inManagedObjectContext:self.managedObjectContext];
ComenziActive *comanda = [NSEntityDescription insertNewObjectForEntityForName:#"ComenziActive" inManagedObjectContext:self.managedObjectContext];
[comanda setValue:sessionController.getSessionUsername forKey:#"numeClient"];
ProdusComandat * produsComandat = [[ProdusComandat alloc]init];
produsComandat.idProdus = [[[(Produs*)produsdb objectID] URIRepresentation] absoluteString];
produsComandat.cantitateComandata = [NSNumber numberWithInteger:[self.cantitateTextField.text integerValue]];
[comanda addProduseComandateObject:produsComandat];
}
else
{
NSError *error;
listaElementeBD = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
ComenziActive *comanda = [listaElementeBD objectAtIndex: 0];
NSArray *produse = comanda.produseComandate.allObjects;
BOOL found =NO;
for(int i=0;i<[produse count];i++)
{
ProdusComandat *p =[[ProdusComandat alloc]init];
p= produse[i];
if ([p.idProdus isEqualToString:[[[(Produs*)produsdb objectID] URIRepresentation] absoluteString]]) {
p.cantitateComandata = [NSNumber numberWithInteger:[p.cantitateComandata integerValue] + [self.cantitateTextField.text integerValue]];
found = YES;
break;
}
}
if (!found) {
ProdusComandat * produsComandat = [[ProdusComandat alloc]init];
produsComandat.idProdus = [[[(Produs*)produsdb objectID] URIRepresentation] absoluteString];
produsComandat.cantitateComandata = [NSNumber numberWithInteger:[self.cantitateTextField.text integerValue]];
[comanda addProduseComandateObject:produsComandat];
}
NSLog(#"============================");
NSLog(#"%#", comanda.produseComandate );
}
NSError *error;
[self.managedObjectContext save:&error];
What I am trying to do is get the data from CoreData entity Produs and copy it's objectID to the entity ProduseComandate that has this relationship ComenziActive<----->>ProduseComandate(relationship one-to-many) if that objectID doesn't exist in the table, but if it does exist, I want to add to the value cantiate some value that I take from the TextField.
The problem was that I needed to declare it like this:
ProdusComandat *produsComandat = [[ProdusComandat alloc]initWithEntity:entity insertIntoManagedObjectContext:self.managedObjectContext];

NSManagedObjectContext work well only a few times, then it stops working

After I tried to ask twice and explain myself, I did a dig and I think I can now explain my problem better:
1) I'm using core data to save to NSManagedObjects: CoreDataTrap & CoreDataAllTraps.
First time, I'm parsing a large xml and then convert to array and then add the details to CoreDataAllTraps, this operation going well as I know because I did a log.
2) Then, Just for the test, I'm fetching all of the records and log the total number of them.
Those functions give me the correct number of records.
3) Then just initializing a few variables.
4) Then initializing my quad tree.
Which gives me back my assertion error.
Error: fetchedObjects have no records.
5) Then, all the rest of the functions that using core data gives me error back of course, because there is no data.
Relevant (numbered) code:
1:
---
- (void)addOrUpdateTrap:(Traps*)trapObject
{
NSManagedObjectContext *context = generateManagedObjectContext();
int trapID = trapObject.getTrapID;
CoreDataAllTraps *trapEntity = nil;
NSError *error = nil;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:kCORE_DATA_ALL_TRAPS_ENTITY];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"trapID == %d", trapID];
[fetchRequest setPredicate:predicate];
NSArray *results = [context executeFetchRequest:fetchRequest error:&error];
if (results == nil)
{
// Handle error
}
else if (results.count == 0)
{
// Nothing to update, add new trap
// Create a new record (row)
trapEntity = [NSEntityDescription insertNewObjectForEntityForName:kCORE_DATA_ALL_TRAPS_ENTITY inManagedObjectContext:context];
}
else
{
trapEntity = results[0]; // There should be only one object for the ID.
}
if (trapEntity != nil)
{
// Set properties for new or existing object ...
// Int
[trapEntity setTrapID:[NSNumber numberWithInt:trapObject.getTrapID]];
[trapEntity setType:[NSNumber numberWithInt:trapObject.getTrapType]];
[trapEntity setDist:[NSNumber numberWithInt:trapObject.getTrapDistanceToCar]];
[trapEntity setDist_to_close_point:[NSNumber numberWithInt:trapObject.getTrapDistanceToClosePoint]];
[trapEntity setActive:[NSNumber numberWithInt:trapObject.isActive]];
[trapEntity setAlert:[NSNumber numberWithInt:trapObject.isAlert]];
[trapEntity setAlarmDistance:[NSNumber numberWithInt:trapObject.alarmDistance]];
[trapEntity setRoadNumber:[NSNumber numberWithInt:trapObject.roadNumber]];
[trapEntity setPolys:[NSNumber numberWithInt:trapObject.polygons]];
[trapEntity setEnter_to_area:[NSNumber numberWithInt:trapObject.getTrapEnterToArea]];
// Double
[trapEntity setLat:[NSNumber numberWithDouble:trapObject.getTrapLat]];
[trapEntity setLon:[NSNumber numberWithDouble:trapObject.getTrapLon]];
[trapEntity setClose_point_lat:[NSNumber numberWithDouble:trapObject.getTrapClosePointLat]];
[trapEntity setClose_point_lon:[NSNumber numberWithDouble:trapObject.getTrapClosePointLon]];
// NSString
[trapEntity setLastTrapAlarm:[NSString stringWithFormat:#"%li", trapObject.getTrapLastAlarm]];
[trapEntity setPoly0:trapObject.getTrapPolygonA];
[trapEntity setPoly1: trapObject.getTrapPolygonB];
[trapEntity setPoly2: trapObject.getTrapPolygonC];
[trapEntity setPolygonAzimut1: trapObject.getTrapPolygonAzimuthA];
[trapEntity setPolygonAzimut2: trapObject.getTrapPolygonAzimuthB];
[trapEntity setPolygonAzimut3: trapObject.getTrapPolygonAzimuthC];
[trapEntity setDesc: trapObject.getTrapDesc];
// etc. for all properties ...
error = nil;
if ([context save:&error] == NO) {
NSLog(#"%s error saving: %#\n%#", __PRETTY_FUNCTION__, error.localizedDescription, error.userInfo);
}
else {
[context reset];
}
}
}
2:
---
- (void)saveArray:(NSArray*)array
{
kNETROADS_CONTEXT.arrayOfAllTraps = self.arrayOfAllTraps = array.mutableCopy;
NSLog(#"Total number of traps: %d", self.arrayOfAllTraps.count);
NSManagedObjectContext *context = generateManagedObjectContext();
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:kCORE_DATA_ALL_TRAPS_ENTITY inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
NSLog(#"TrapService - fetchedObjects.count: %d", fetchedObjects.count);
if (fetchedObjects == nil || fetchedObjects.count == 0) {
NSLog(#"saveArray - localizedDescription: %#, userInfo: %#", error.localizedDescription, error.userInfo);
}
[self readArray];
}
- (void)readArray
{
NSManagedObjectContext *context = generateManagedObjectContext();
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:kCORE_DATA_ALL_TRAPS_ENTITY inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
NSLog(#"readArray - fetchedObjects.count: %d", fetchedObjects.count);
if (fetchedObjects == nil || fetchedObjects.count == 0) {
NSLog(#"readArray - localizedDescription: %#, userInfo: %#", error.localizedDescription, error.userInfo);
}
}
3:
---
- (void)initVariables
{
db = [[DataBase alloc] init];
//dbat = [[DataBaseAllTraps alloc] init];
dbat = [DataBaseAllTraps getInstance];
kRECEIVER_CONTEXT.db = [[DataBase alloc] init];
[db deleteTrapsTable];
[dbat deleteTrapsTable];
self.dictAddUserLocations = [[NSMutableDictionary alloc] init];
self.arrayOfAllTraps = [Netroads sharedInstance].arrayOfAllTraps;
self.arrayOfLocations = [[NSMutableArray alloc] init];
self.firstOnLocationChanged = YES;
self.mLocation = [CLLocation new];
self.mLastLocation = [CLLocation new];
self.globalLocation = [CLLocation new];
self.lastGlobalLocation = [CLLocation new];
self.myLocations = [[NSMutableArray alloc] init];
self.accuracy = #"N/A";
self.closeTrap = [[Traps alloc] init];
self.notification = [NSNotificationCenter defaultCenter];
// [self.notification addObserver:self selector:#selector(onReceive:) name:kSend_To_Receiver_Notification object:nil];
}
4:
---
- (void)initializeQuadTree
{
self.qTree = [[QuadTree alloc] init];
BOOL success = YES;
NSManagedObjectContext *context = generateManagedObjectContext();
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:kCORE_DATA_ALL_TRAPS_ENTITY inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil || fetchedObjects.count == 0)
{
NSLog(#"initializeQuadTree - localizedDescription: %#, userInfo: %#", error.localizedDescription, error.userInfo);
success = NO;
}
NSLog(#"initializeQuadTree - fetchedObjects.count: %d", fetchedObjects.count);
NSAssert(fetchedObjects != nil, #"Error: fetchedObjects = nil");
NSAssert(fetchedObjects.count > 0, #"Error: fetchedObjects have no records.");
if (success)
{
for (CoreDataAllTraps *trap in fetchedObjects)
{
double latitude = trap.lat.doubleValue;
double longitude = trap.lon.doubleValue;
double closePointLat = trap.close_point_lat.doubleValue;
double closePointLon = trap.close_point_lon.doubleValue;
DummyAnnotation *trapAnnotation = [[DummyAnnotation alloc] init];
if (closePointLat != 0.0 || closePointLon != 0.0) trapAnnotation.coordinate = CLLocationCoordinate2DMake(closePointLat, closePointLon);
else trapAnnotation.coordinate = CLLocationCoordinate2DMake(latitude, longitude);
[self.qTree insertObject:trapAnnotation];
}
}
else
{
for (Traps *trap in kNETROADS_CONTEXT.arrayOfAllTraps)
{
double latitude = trap.lat;
double longitude = trap.lon;
double closePointLat = trap.closePointLat;
double closePointLon = trap.closePointLon;
DummyAnnotation *trapAnnotation = [[DummyAnnotation alloc] init];
if (closePointLat != 0.0 || closePointLon != 0.0) trapAnnotation.coordinate = CLLocationCoordinate2DMake(closePointLat, closePointLon);
else trapAnnotation.coordinate = CLLocationCoordinate2DMake(latitude, longitude);
[self.qTree insertObject:trapAnnotation];
}
}
NSLog(#"TOTAL NUMBER OF TRAPS (%s): %i", __PRETTY_FUNCTION__, success?fetchedObjects.count:[Netroads sharedInstance].arrayOfAllTraps.count);
}
Side notes:
* After calling initializeQuadTree i'm initializing the location manager.
* In location manager I've a dispatch_async that wrap the whole code inside.
* After I done with all initializing, the main of the code happens via location manager didUpdateLocations.
* For each and every using in core data I'm generating new NSManagedObjectConext like this:
FOUNDATION_EXPORT NSManagedObjectContext *generateManagedObjectContext()
{
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init];
context.persistentStoreCoordinator = appDelegate.persistentStoreCoordinator;
return context;
}
[db deleteTrapsTable];
[dbat deleteTrapsTable];
The table deleted after you create it

How to make a conditional request with NSManagedObjectContext?

I'm new to NSManagedObjectContext. I have created an entity Link in my app, which contains a NSString *url.
At some point of my app, I need to insert a new Link in my base, so I simply do this :
Link *link = [NSEntityDescription
insertNewObjectForEntityForName:#"Link"
inManagedObjectContext:self.managedObjectContext];
link.url = myUrl;
But before doing this, I want to check if there is not already a Link in my base with the same url. And I have no idea of how to do so... what should I do?
EDIT : to retrieve data from the base I'm using this method from a tool I found on the web:
// Fetch objects with a predicate
+(NSMutableArray *)searchObjectsForEntity:(NSString*)entityName withPredicate:(NSPredicate *)predicate andSortKey:(NSString*)sortKey andSortAscending:(BOOL)sortAscending andContext:(NSManagedObjectContext *)managedObjectContext
{
// Create fetch request
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
// If a predicate was specified then use it in the request
if (predicate != nil)
[request setPredicate:predicate];
// If a sort key was passed then use it in the request
if (sortKey != nil) {
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortKey ascending:sortAscending];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
}
// Execute the fetch request
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
// If the returned array was nil then there was an error
if (mutableFetchResults == nil)
NSLog(#"Couldn't get objects for entity %#", entityName);
// Return the results
return mutableFetchResults;
}
I would like to know how to use it.
Thanks for your help.
The method you provided just searches for a NSManagedObject that matches the attributes in the NSManagedObjectContext and if one exists, it returns it.
But, what you need to implement is called the Find-or-Create pattern, which is discussed in the Core Data programming guide. Basically, you search for an object matching specific criteria and if it exists that object is returned. If that object does not exist you create it.
Core Data Programming Guide
E.g.
+ (NSString *)entityName
{
return NSStringFromClass([Link class]);
}
+ (instancetype)findUsingPredicate:(NSPredicate *)predicate withContext:(NSManagedObjectContext *)context
{
Link * entity;
// Setup the fetchRequest
NSFetchRequest * fetchRequest = [NSFetchRequest fetchRequestWithEntityName:[[self class] entityName]];
fetchRequest.predicate = predicate;
// Credit: #Martin R
[fetchRequest setFetchLimit:1];
// Execute the fetchRequest
NSError *error = nil;
NSArray * matchingLinks = [context executeFetchRequest:fetchRequest error:&error];
// MatchingLinks will only return nil if an error has occurred otherwise it will return 0
if (!matchingLinks)
{
// handle error
// Core data returns nil if an error occured
NSLog(#"%s %#", __PRETTY_FUNCTION__, [error description]);
}
else if ([matchingLinks count] <= 0)
{
// if the count <= 0, there were no matches
NSLog(#"%s Not found", __PRETTY_FUNCTION__);
} else {
// A link with a url that matches the url in the dictionary was found.
NSLog(#"%s Found", __PRETTY_FUNCTION__);
entity = [matchingLinks lastObject];
}
return entity;
}
+ (instancetype)findUsingPredicate:(NSPredicate *)predicate orCreateWithContext:(NSManagedObjectContext *)context
{
Link * entity = [[self class] findUsingPredicate:predicate withContext:context];
if (!entity) {
entity = [[self class] createWithContext:context];
}
return entity;
}
+ (isntancetype)createWithContext:(NSManagedObjectContext *)context
{
return [[self class] alloc] initWithContext:context];
}
- (instancetype)initWithContext:(NSManagedObjectContext *)context
{
Link * entity = [NSEntityDescription insertNewObjectForEntityForName:[[self class] entityName] inManagedObjectContext:context];
return entity;
}
USE CASE:
NSString * url = #"http://www.mylink.com";
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"url = %#", url];
Link * link = [Link findUsingPredicate:predicate orCreateWithContext:self.managedObjectContext];
link.url = url;
You can do it like this (with your method):
AppDelegate *del = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *managedObjectContext = del.managedObjectContext;
NSString *urlString = #"YOUR URL HERE";
NSMutableArray *fetchedResults = [self searchObjectsForEntity:#"Link" withPredicate:[NSPredicate predicateWithFormat:#"url == %#", urlString] andSortKey:#"url" andSortAscending:YES andContext:managedObjectContext];
BOOL exist = NO;
if(fetchedResults.count >= 1){
exist = YES;
}

Resources