I have a coredata project that I’m trying to programmatically update a number.
I’m retrieving objects from CoreData and then storing it into an array.
Then, I’m looping through that array to see if the current user’s IP is present in the database and trying to update the number of times accessed for that specific array.
The problem is, it’s updating all the objects, not just the current object in the looped array.
First, I get the info from core data like so:
- (void)fetchRecords {
// Define our table/entity to use
NSEntityDescription *entity = [NSEntityDescription entityForName:@"IPAddr" inManagedObjectContext:managedObjectContext];
// Setup the fetch request
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
// Define how we will sort the records
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"ipDate" ascending:NO];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
[request setSortDescriptors:sortDescriptors];
// Fetch the records and handle an error
NSError *error;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (!mutableFetchResults) {
// Handle the error.
// This is a serious error and should advise the user to restart the application
}
// Save our fetched data to an array
[self setIpArray: mutableFetchResults];
}
Now, I’m trying to find if the current User IP is present in the fetched results, and if it’s present, update the number of times accessed:
// see if the ip is present and update if necessary
-(void)ipPresent {
NSString * theCurrentIP = [self getGlobalIPAddress];
for (IPAddr *allips in ipArray)
{
if ([allips.ipNum isEqualToString:theCurrentIP]) {
NSLog(@"The IP %@ was found.", theCurrentIP);
// update the ip
NSError *error = nil;
NSNumber *ipToUpdate = allips.ipAccess;
NSNumber *addIpAccess = [[NSNumber alloc] initWithInt:1];
NSNumber *updateIpAddress = [NSNumber numberWithFloat:([ipToUpdate floatValue] + [addIpAccess floatValue])];
[self.ipArray setValue:updateIpAddress forKey:@"ipAccess"];
if ([self.managedObjectContext save:&error]) { // write to database
NSLog(@"The IP Was Updated from %@ to %@", ipToUpdate, updateIpAddress);
} else if (![self.managedObjectContext save:&error]) {
NSLog(@"failed with error: %@", error);
}
break;
} else {
NSLog(@"The IP %@ was NOT found.", theCurrentIP);
}
}
}
I’m pretty sure the issue is with this line:
[self.ipArray setValue:updateIpAddress forKey:@"ipAccess"];
Again, it’s updating ALL the entities and not just the one in the current loop.
Indeed. You are using the wrong method.
self.ipArrayis aNSMutableArray.The method
is used for Key-Value Coding (which is what makes it work for Core Data objects), but when applied to an array, it will invoke setValue:forKey: on each entry in the array.
Now, you can see that you could also call
setValue:forKeyon the one single array elementallipssince its property is obviously KVC compliant — otherwise you would be having a different problem, not see the values being set.Note, that you could also just assign the property…
EDIT
Sorry, probably should have read slower… You do understand that you don’t have to use a mutable array, right? You are not actually changing the array, just the elements in the array. An immutable collection means that the collection contents can not change, but when you have a pointer to an object, as long as that object is not immutable, you can still mutate its properties.
Thus, if you had an immutable array of Foo objects, you could do this…
If, however, you call
setValue:forKeyon the array, it will be invoked for each element of the array. Note, thatsetValue:forKeyis actually declared in the immutable NSArray.EDIT
That comment was hard to read.
The core data object is just another object. It looks like you have subclassed it, and provided it with properties for the attributes. Just replace
with
or
Either of those should modify your core data object, as they would any object that had a read/write property named “ipAccess”
Assuming, of course, that I didn’t read it wrong again… and allips is your core data object…