Cannot perform operation without a managed object context - ios

I'm trying add items from core data query to nsmutablearray but I'm getting this error:
"Cannot perform operation without a managed object context"
Here is my code:
NSPredicate *productPredicate = [NSPredicate predicateWithFormat:#"TRUEPREDICATE"];
NSManagedObjectContext *moc = self.managedObjectContext;
NSEntityDescription *description = [ NSEntityDescription entityForName:#"Product" inManagedObjectContext:moc];
NSFetchRequest *request = [NSFetchRequest new];
request.predicate = productPredicate;
request.entity = description;
NSError *error = nil;
NSArray *results = [moc executeFetchRequest:request error:&error];
for (NSInteger i = 0; i < results.count; i++)
{
NSString *productName = [[results objectAtIndex:i] valueForKey:#"productName"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"productName == %#", productName];
NSArray *match = [_listOfProducts filteredArrayUsingPredicate:predicate];
if (match == 0)
{
[self.listOfProducts addObject:[results objectAtIndex:i]];
}
}
Where I'm getting the error is at the momento of adding the object to nsmutablearray:
[self.listOfProducts addObject:[results objectAtIndex:i]];
Any of you knows why I'm getting this error?, I'll really appreciate your help.

Related

Delete record from core data not working?

I am working with core data, when I deleting record from DB it's not working.
Entity name : Entity
Attributes : id, date, title
- (void) getData {
NSFetchRequest * fetReq = [NSFetchRequest fetchRequestWithEntityName:#"Entity"];
NSError * fetchErrorObj;
NSArray *result = [self.ad.managedObjectContext executeFetchRequest:fetReq error:&fetchErrorObj];
NSLog(#"array count is %lu", result.count);
NSMutableArray *idArr = [[NSMutableArray alloc]init];
NSMutableArray *titleArr = [[NSMutableArray alloc]init];
NSMutableArray *dateArr = [[NSMutableArray alloc]init];
for (int i=0; i<result.count; i++) {
self.storedManagedObj = [result objectAtIndex:i];
[idArr addObject:[self.storedManagedObj valueForKey:#"id"]];
[titleArr addObject:[self.storedManagedObj valueForKey:#"title"]];
[dateArr addObject:[self.storedManagedObj valueForKey:#"date"]];
}
self.idArray = sidArr;
}
To delete record...
- (IBAction)deleteRecord:(UIButton *)sender {
NSNumber *value=[NSNumber numberWithInt:[[self.idArray objectAtIndex:0] intValue]];
NSLog(#"%#", [self.idArray objectAtIndex:0]);
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:#"Entity"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"id == %#", value];
NSLog(#"predicate :%#", predicate);
[request setPredicate:predicate];
NSLog(#"request :%#", request);
NSError *error = nil;
NSArray *result = [self.ad.managedObjectContext executeFetchRequest:request error:&error];
NSLog(#"result: %#", result);
if (!error && result.count > 0) {
for(NSManagedObject *managedObject in result){
NSLog(#"managedObject :%#", managedObject);
[self.ad.managedObjectContext deleteObject:managedObject];
}
//Save context to write to store
[self.ad.managedObjectContext save:nil];
}
}
I am getting result like this
predicate :id == 38
request : (entity: Entity; predicate: (id == 38); sortDescriptors: ((null)); type: NSManagedObjectResultType; )
result :(
)
The error is pretty clear. It states that you need to specify SortDescriptor to your FetchRequest
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:#"Entity"];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"<#Sort key#>"
ascending:YES];
request.sortDescriptors = #[sortDescriptor];
OR
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects: sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
Read : NSFetchRequest without sort descriptors
EDIT:
As OP isn't concerned about sorting the result in any specific order and the question lacks the description of entity and the only field that I can see in question is id updating my answer to use id in sort descriptor field
[[NSSortDescriptor alloc] initWithKey:#"id" ascending:YES];
EDIT 2:
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:#"Entity"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"id == %#", [self.idArray objectAtIndex:0]];
Issue in the code was :
NSNumber *value=[NSNumber numberWithInt:[[self.idArray objectAtIndex:0] intValue]];
OP was trying to create a NSNumber from an object in self.idArray using intValue which means idArray is a array of String and not NSNumber. That means id is saved as String in core data and not as NSNumber.
In predicate however OP was trying to pass NSNumber to compare with id. Since id is String and passed argument is NSNumber comparison was failing hence was not returning any objects.

I cannot insert value with NSNumber datatype into my coredata

Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: 'Unacceptable type of value for
attribute: property = "XXXXX"; desired type = NSNumber; given type =
NSTaggedPointerString; value = 0.'
Tried: [enter image description here][1]
[message setValue:localID forKey:#"local_id"];
localID is of type NSNumber
DataModel image: [1]: https://i.stack.imgur.com/7WTlU.png
[self insertInLocatDB:print_data entityName:#"Message_data" withPredicate:#"receiver_id" filterWith:#"unique_id"];
Using this to insert into CoreData:
-(void)insertInLocatDB :(NSMutableArray *)arr_msg entityName:(NSString*)name withPredicate:(NSString*)predicateText filterWith:(NSString*)filterText
{
NSEntityDescription *entitydesc=[NSEntityDescription entityForName:name inManagedObjectContext:app.context];
NSFetchRequest *request=[[NSFetchRequest alloc]init];
[request setEntity:entitydesc];
NSInteger local_id =[self getMaxLocalId:name];
for(int i=0; i<[arr_msg count]; i++)
{
[fetched_data removeAllObjects];
NSPredicate *predicate =[NSPredicate predicateWithFormat:#"%# like %# ",predicateText,[[arr_msg objectAtIndex:i]objectForKey:predicateText]];
[request setPredicate:predicate];
NSError *error;
NSArray *matchingData=[app.context executeFetchRequest:request error:&error];
local_id=local_id+1;
for (NSManagedObject *obj in matchingData)
{
[fetched_data addObject:[obj valueForKey:filterText]];
}
NSString *filter=[[arr_msg objectAtIndex:i] objectForKey:filterText];
if(![fetched_data containsObject:filter])
{
NSManagedObject *message=[[NSManagedObject alloc] initWithEntity:entitydesc insertIntoManagedObjectContext:app.context];
[arr_keys setArray:[[arr_msg objectAtIndex:i] allKeys]];
[arr_values setArray:[[arr_msg objectAtIndex:i] allValues]];
[message setValue:[NSNumber numberWithInteger:local_id] forKey:#"local_id"];
for (int i=0;i<[arr_keys count];i++)
{
if( [[message.entity propertiesByName] objectForKey:[arr_keys objectAtIndex:i]] != nil
&& ([[[message.entity propertiesByName] objectForKey:[arr_keys objectAtIndex:i]] isKindOfClass:[NSAttributeDescription class]]) )
{
[message setValue:[arr_values objectAtIndex:i] forKey:[arr_keys objectAtIndex:i]];
}
}
[arr_keys removeAllObjects];
[arr_values removeAllObjects];
}
}
}
If you have a core data attribute as shown in my screen shot.
Then, the following snippet of code will work for you.
BOOL result;
NSManagedObjectContext *context = [self managedObjectContext];
// Create a new managed object
NSManagedObject *newMessage = [NSEntityDescription insertNewObjectForEntityForName:#"message"
inManagedObjectContext:context];
[newMessage setValue:[NSNumber numberWithInt:local_id] forKey:#"local_id"];
[newMovie setValue:movieName forKey:#"message"];
NSError *error = nil;
// Save the object to persistent store
result = YES;
if (![context save:&error]) {
result = NO;
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
return result;
and a function to get the managed object context
- (NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
Edited Code of Sandhya.
-(NSInteger)getMaxLocalId :(NSString*)entitiyName
{
NSEntityDescription *entitydesc=[NSEntityDescription entityForName:entitiyName inManagedObjectContext:app.context];
NSFetchRequest *request=[[NSFetchRequest alloc]init];
[request setEntity:entitydesc];
NSInteger local_id = 0;
request.fetchLimit = 1;
request.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"local_id" ascending:NO]];
NSError *error = nil;
local_id=[[app.context executeFetchRequest:request error:&error].firstObject integerValue];
return local_id;
}
Then used the following to insert in to CoreData
NSInteger local_id =[self getMaxLocalId:name];
local_id=local_id+1;
[message setValue:[NSNumber numberWithInteger:local_id] forKey:#"local_id"];
make sure you get the local_id.
As you have NSInteger, For conversion you should use [NSNumber numberWithInteger:] Instead of [NSNumber numberWithInt:]
UPDATE 2 :
NSString *filter=[[arr_msg objectAtIndex:i] objectForKey:filterText];
if(![fetched_data containsObject:filter])
{
NSManagedObject *message=[[NSManagedObject alloc] initWithEntity:entitydesc insertIntoManagedObjectContext:app.context];
[arr_keys setArray:[[arr_msg objectAtIndex:i] allKeys]];
[arr_values setArray:[[arr_msg objectAtIndex:i] allValues]];
[message setValue:[NSNumber numberWithInteger:local_id] forKey:#"local_id"];
for (int i=0;i<[arr_keys count];i++)
{
if( [[message.entity propertiesByName] objectForKey:[arr_keys objectAtIndex:i]] != nil
&& ([[[message.entity propertiesByName] objectForKey:[arr_keys objectAtIndex:i]] isKindOfClass:[NSAttributeDescription class]]) )
{
if(![[arr_keys objectAtIndex:i] isEqualToString:#"local_id"]){
[message setValue:[arr_values objectAtIndex:i] forKey:[arr_keys objectAtIndex:i]];
}
}
}
[arr_keys removeAllObjects];
[arr_values removeAllObjects];
}
-(NSInteger)getMaxLocalId :(NSString*)entitiyName
{
NSEntityDescription *entitydesc=[NSEntityDescription entityForName:entitiyName inManagedObjectContext:app.context];
NSFetchRequest *request=[[NSFetchRequest alloc]init];
[request setEntity:entitydesc];
NSInteger local_id = 0;
request.fetchLimit = 1;
request.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"local_id" ascending:NO]];
NSError *error = nil;
local_id=[[app.context executeFetchRequest:request error:&error].firstObject integerValue];
return local_id;
}
Then used the following to insert in to CoreData
NSInteger local_id =[self getMaxLocalId:name];
local_id=local_id+1;
[message setValue:myNumber forKey:#"local_id"];

Exactly Matched NSString in Core Data iOS

I've my entity in CoreData named as myentity and an attribute named as myuniqueid and I want to run an SQL query as follows:
Select * from myentity where myuniqueid == 1000
How can I get my specified rows where it matches as in SQL query? such that I want to filter all rows where myuniqueid is 1000.
My Code:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSManagedObjectContext *context = [self managedObjectContext];
if (context == nil) {}
else {
NSEntityDescription *entity = [NSEntityDescription entityForName:#"myentity" inManagedObjectContext:context];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"myuniqueid == 1000"];
[fetchRequest setPredicate:predicate];
[fetchRequest setEntity:entity];
NSArray *items = [context executeFetchRequest:fetchRequest error:nil];
for (int i=0; i<4; i++) {
NSManagedObject *mo = [items objectAtIndex:i]; // assuming that array is not empty
id value = [mo valueForKey:#"myuniqueid"];
NSLog(#"SENDER: %#",value);
}
}
Im getting error: 'Unable to generate SQL for predicate (myuniqueid == 1000) (problem on RHS)'
Try this predicate :
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"myentity"];
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"myuniqueid == %#", #(1000)];
NSArray *items = [[self managedObjectContext] executeFetchRequest:request error:nil];

Issue with Coredata update

I'm trying to update certain currency abbreviations in the coredata with this function.
- (void)updateCurrencies
{
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:#"Transaction" inManagedObjectContext:managedObjectContext]];
NSError *error = nil;
NSArray *results = [managedObjectContext executeFetchRequest:request error:&error];
NSLog(#"Number of data : %lu", (unsigned long)[results count]);
for (int i = 0; i < [results count]; i++) {
Transaction* t = [results objectAtIndex:0];
NSLog(#"currency: %#", t.currency);
if ([t.currency isEqualToString:#"CAN"]) {
t.currency = #"CAD";
NSLog(#"new currency set.");
}
[self saveContext];
}
}
}
I call this function in didFinishLaunchingWithOptions. Now, the log does inform me that t.currency has been updated to CAD. However when I retrieve the data again in HomeViewController and log the currency, it is back to CAN. This is the code in HomeViewController,
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *transaction = [NSEntityDescription entityForName:#"Transaction" inManagedObjectContext:_managedObjectContext];
[request setEntity:transaction];
request.predicate = [NSPredicate predicateWithFormat:#"transactionToUser = %#", [self.content objectAtIndex:i]];
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"postdate" ascending:NO];
NSArray *descriptors = [[NSArray alloc] initWithObjects:descriptor, nil];
[request setSortDescriptors:descriptors];
NSError *error = nil;
NSMutableArray *mutableResult = [[_managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (mutableResult == nil) {
//handle error
}
for (int k = 0; k < [mutableResult count]; k++) {
Transaction *t = [mutableResult objectAtIndex:k];
NSLog(#"currency xx: %#", t.currency);
}
What am I doing wrong? Any help is appreciated. Thanks.
Fixed it with a different for loop.
for (Transaction *t in results)
{
...
}

XMPP, CoreData - how to load only self and destination user messages?

I save to core data and load all messages with code below, but how can I load only messages for 2 users, for self user and for destination user, I want base it on user JID.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSManagedObjectContext *context = [[self appDelegate].xmppMessageArchivingCoreDataStorage mainThreadManagedObjectContext];
NSEntityDescription *messageEntity = [NSEntityDescription entityForName:#"XMPPMessageArchiving_Message_CoreDataObject" inManagedObjectContext:context];
fetchRequest.entity = messageEntity;
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"timestamp" ascending:YES];
fetchRequest.sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSError *error = nil;
NSArray *results = [context executeFetchRequest:fetchRequest error:&error];
//Now you get the NSArray with element type of "XMPPMessageArchiving_Message_CoreDataObject"
assuming your message objects have a from relationshit to a User entity.
As simple as adding (before executing the request):
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"from = %# OR from = %#",selfUser,otherUser];
Where selfUser and otherUser are User core data managed objects or managed object IDs of users.
if you use a field identifier (highly not recomended):
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"bareJID.bare = %# OR bareJID.bare = %#",selfUser.jid,otherUser.jid];
You might want to read THIS
I have used following method and it worked correctly :)
-(void)checkForPastMessageAndDisplayIt
{
NSString *strmyid = #"user1#domain";
NSString *strBuddy = #"user2#domain";
NSManagedObjectContext *moc = [[self appDelegate] managedObjectContext_message_achiving];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"XMPPMessageArchiving_Message_CoreDataObject"
inManagedObjectContext:moc];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"bareJidStr = %# OR bareJidStr = %#", strmyid, strBuddy];
[fetchRequest setEntity:entity];
NSError *error;
NSArray *messagesArray = [moc executeFetchRequest:fetchRequest error:&error];
[messagesArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
id messageObject = [messagesArray objectAtIndex:idx];
if ([messageObject isKindOfClass:[XMPPMessageArchiving_Message_CoreDataObject class]]) {
XMPPMessageArchiving_Message_CoreDataObject *currentMessageCoreDataObject = (XMPPMessageArchiving_Message_CoreDataObject*)messageObject;
XMPPMessage *message = currentMessageCoreDataObject.message;
if (message!=nil) {
[messages addObject:message];
}
}
}];
}
You can use like that
-(void)testMessageArchiving {
NSString *strmyid = #"myid";
NSString *strBuddy ="toid";
NSLog(#"my id and buddy is is %# and %#",strmyid,strBuddy);
XMPPMessageArchivingCoreDataStorage *storage = [XMPPMessageArchivingCoreDataStorage sharedInstance];
NSManagedObjectContext *moc = [storage mainThreadManagedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"XMPPMessageArchiving_Message_CoreDataObject"
inManagedObjectContext:moc];
NSFetchRequest *request = [[NSFetchRequest alloc]init];
request.predicate = [NSPredicate predicateWithFormat:#"bareJidStr = %# OR bareJidStr = %#", strmyid, strBuddy];
NSError *error;
NSArray *messages = [moc executeFetchRequest:request error:&error];
// NSLog(#"the history of messages is %#",messages);
[self print:[[NSMutableArray alloc]initWithArray:messages]];

Resources