I'm trying to insert a new object to my core data.
I inserted this way in previous app and it was ok.
Here is the function
_appDelegte=[UIApplication sharedApplication].delegate;
self.managedObjectContext = _appDelegte.managedObjectContext;
#try {
Album *album=[NSEntityDescription insertNewObjectForEntityForName:[AlbumTable tableName] inManagedObjectContext:self.managedObjectContext];
//Insert Values
album.albumId=albumId;
album.code=code;
album.name=name;
album.facebookAccessToken=facebookAccessToken;
album.facebookExpires=facebookExpires;
album.albumDescription=description;
album.startTime=startTime;
album.endTime=endTime;
album.latitude=latitude;
album.longitude=longitude;
album.placeName=placeName;
album.ownerFacebookId=ownerFacebookId;
album.isWatermark=isWatermark;
return YES;
}
#catch (NSException *exception) {
NSLog(#"Insert exception - %#", exception.description);
return NO;
}
Later in the app' i'm trying to get the object out and it's nil.
// initializing NSFetchRequest
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
//Setting Entity to be Queried
NSEntityDescription *entity = [NSEntityDescription entityForName:[AlbumTable tableName] inManagedObjectContext:_appDelegte.managedObjectContext];
[fetchRequest setEntity:entity];
NSError* error;
// Query on managedObjectContext With Generated fetchRequest
NSArray *fetchedRecords = [_appDelegte.managedObjectContext executeFetchRequest:fetchRequest error:&error];
// Returning albums as an array
for (Album *album in fetchedRecords) {
return album;
}
return nil;
Any idea why?
Check if
Context is not nil
You call save: on the context
Other conspicuous points: the following line of code.
Album *album=[NSEntityDescription insertNewObjectForEntityForName:[AlbumTable tableName] inManagedObjectContext:self.managedObjectContext];
You have a class album table that returns the table name. I would not advise to use something this complicated. Simply use a string #"Album".
and this
// Returning albums as an array
for (Album *album in fetchedRecords) {
return album;
}
This is not returning the albums as an array. It just returns the first album of the array. Make sure that also the fetch situation has a non-nilmanaged object context.
Related
I have 2 Entities: Goal and Category. I added relationship "category" to Goal entity. I want that user can choose a category from list and then that category added as relation to Goal object. But I getting error: -[__NSSingleObjectSetI managedObjectContext]: unrecognized selector sent to instance 0x138a22fa0
My code:
- (BOOL)save {
// Get Category object
NSManagedObject *objCategory = [self getCategoryObjectWithID:#"1"];
if (!objCategory) {
NSLog(#"ERROR objCategory fetching!");
return;
}
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Goal"
inManagedObjectContext:[CoreDataWrapper myManagedContext]];
NSManagedObject *goal = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:[CoreDataWrapper myManagedContext]];
[goal setValue:strID forKey:#"id"];
[goal setValue:[NSSet setWithObject:objCategory] forKey:#"category"]; // here error
return [CoreDataWrapper saveMyContext];
}
- (NSManagedObject *)getCategoryObjectWithID:(NSString *)catID {
// Fetching
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Category"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K == %#", #"categoryID", catID];
[fetchRequest setPredicate:predicate];
// Execute Fetch Request
NSError *fetchError = nil;
NSArray *result = [[CoreDataWrapper myManagedContext] executeFetchRequest:fetchRequest error:&fetchError];
if (!fetchError) {
return result[0];
}
return nil;
}
I'm new to CoreData and maybe this some sort of dumb questions, but I followed many resourses and can't find what's a problem.
If your Goal object can only have one category, then it's a to-one relationship, meaning that the category property is an object, not a set of objects (not even a set of 1 object).
You should set your category like so :
[goal setValue:objCategory forKey:#"category"];
I've just read some tutorials and decide to add Core Data storage to my project. Then I implement "create" and "read" methods. It works OK.
But then I encountered a problem with "update" method.
- (void)updateForecastPlace:(NSString *)placeString
{
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:ENTITY_NAME inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
WFForecast *forecastToUpdate;
for (WFForecast *forecast in fetchedObjects)
{
if ([[forecastToUpdate timestamp] compare:[forecast timestamp]] == NSOrderedAscending)
{
forecastToUpdate = forecast;
}
}
[forecastToUpdate setPlace:placeString];
error = nil;
if ([context save:&error])
{
NSLog(#"Forecast information was updated!");
}
else
{
NSLog(#"The forecast information was not updated: %#", [error userInfo]);
}
}
I'm fetching objects from context. (It's OK)
Then choose one to update.
Setup new value to its property( [forecastToUpdate setPlace:placeString];)
Then save the context. ( [context save:&error] )
It seems like it works (it's rise no errors and send success massage to console log). But when I read this object it appears to be non-updated.
I read a lot of stuff on this problem but didn't figure out how to fix it.
Any suggestions, please?
UPDATE: I check the value of my updated object property place
[forecastToUpdate setPlace:placeString];
NSLog(#"---arg value %#", placeString);
NSLog(#"---updated value %#", [forecastToUpdate place]);
and got the output like:
---arg value Sydney, Australia
---updated value (null)
Any idea what caused such mistake?
Unfortunately the problem was in my inattentiveness :(
I forgot to assign fetched object with my objectToUpdate pointer before compare values and do other stuff.
WFForecast *lastestForecast = fetchedObjects[0]; // <- missed this row
for (WFForecast *forecast in fetchedObjects)
{
NSLog(#"%#", [forecast place]);
if ([[lastestForecast timestamp] compare:[forecast timestamp]] == NSOrderedAscending)
{
lastestForecast = forecast;
}
}
I am in a situation where i need to update transformable attribute in my entity in core data, until now i've tried every possible answer from google and stack overflow but did't achieve anything.
This is the method where i am saving object in core data, and my object which i am saving is an NSMutablDictionary type object.
-(void)didSaveToCoreData :(NSMutableDictionary *)newDict
{
#try {
AppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
NSManagedObjectContext *context = appDelegate.managedObjectContext ;
DataModelSupport *entity = [NSEntityDescription insertNewObjectForEntityForName:#"CPIEntity" inManagedObjectContext:context];
if (newDict != nil) {
[entity.fixed_Model removeAllObjects];
entity.fixed_Model = newDict;
}
NSError *error ;
[context save:&error];
if(error)
{
NSLog(#"Error in Saving Data");
}
else
{
[self didFetchFromCoreDataModel];
NSLog(#"Successfully saved");
}
}
#catch (NSException *exception) {
[self spareMeFromTheCrash:exception];
}
#finally {
}
}
in this method i am saving a dictionary object of 19 key/value, at the first time and i am fetching it correctly in didFetchFromCoreDataModel method, but when i refresh the data and get dictionary of 18 key/value i save that dictionary in core data using the same method didSaveToCoreData and fetch it in the same way from didFetchFromCoreDataModel but it still show 19 key/value
DataModelSupport is a subclass of NSManagedObject.
In DataModelSupport.h:
#property (nonatomic,weak) NSMutableDictionary *fixed_Model;
In DataModelSupport.m:
#dynamic fixed_Model;
This is it for the DataModelSupport class.
Now here in this method i am fetching the same object form core data
-(void)didFetchFromCoreDataModel
{
#try {
AppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
NSManagedObjectContext *context = appDelegate.managedObjectContext ;
NSEntityDescription *entity = [NSEntityDescription entityForName:#"CPIEntity" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc]init];
[request setReturnsDistinctResults:YES];
[request setReturnsObjectsAsFaults:NO];
[request setResultType:NSDictionaryResultType];
[request setEntity:entity];
NSError *error ;
NSArray *arr = [context executeFetchRequest:request error:&error];
updatedfinalArr = [arr valueForKey:#"fixed_Model"];
if(error)
{
NSLog(#"Error");
}
else
{
}
}
#catch (NSException *exception) {
[self spareMeFromTheCrash:exception];
}
#finally {
}
}
And this is how my core data looks like:-
Any help is appreciated.
EDIT
I've implemented some changes in my code now in didSaveToCoreData method i am using this line of code to fetch the Entity by name
NSEntityDescription *descriptor = [NSEntityDescription entityForName:#"CPIEntity" inManagedObjectContext:context];
by this i am not creating new entity every time i call didSaveToCoreData method.
and this is how i am saving NSMutlableDictionary object
DataModelSupport *entity = [[DataModelSupport alloc]initWithEntity:descriptor insertIntoManagedObjectContext:context];
[entity.fixed_Model removeAllObjects]
entity.fixed_Model = newDict;
but still i am not getting correct result.
now when i refresh the data and save it using the above procedure explained in EDIT section, and fetch it, i get the updated data but it increase the number of objects, like on first attempt when i fetch i got 1 object in array, and on second attempt i got 2 objects and it goes like this, so when ever new data is added its not updating it but instead it add it in the entity s fixed_Model attribute and increase the number of object.
Lastly now i am using this line of code to get the last and update object from array in didFetchFromCoreDataModel method
NSDictionary *ddd = [[arr valueForKey:#"fixed_Model"]lastObject];
updatedfinalArr = [NSMutableArray arrayWithObject:ddd];
Your save method creates a new CPIEntity object each time. So, unless you delete the old object elsewhere in your code, I suspect your fetch is returning several objects, the first of which has the dictionary with 19 key/value pairs in the fixed_Model attribute, and the second/subsequent objects contain the 18 key/value pairs.
When you save, you should try to fetch the existing object first, and if you get zero results then create a new object. Then set the fixed_Model attribute of the new/existing object to your new dictionary.
EDIT
You are still inserting a new object each time (DataModelSupport *entity = [[DataModelSupport alloc]initWithEntity:descriptor insertIntoManagedObjectContext:context];). See below for an example of "fetch or create":
AppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
NSManagedObjectContext *context = appDelegate.managedObjectContext ;
NSEntityDescription *descriptor = [NSEntityDescription entityForName:#"CPIEntity" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc]init];
request.entity = descriptor;
NSError *error;
NSArray *results = [context executeFetchRequest:request error:&error];
if (results == nil) {
// This implies an error has occurred.
NSLog(#"Error from Core Data: %#", error);
} else {
if (results.count == 0) {
// No objects saved, create a new one...
DataModelSupport *entity = [[DataModelSupport alloc]initWithEntity:descriptor insertIntoManagedObjectContext:context];
entity.fixed_Model = newDict;
} else {
// At least one object saved. There should be only one
// so use the first...
DataModelSupport *entity = [results firstObject];
entity.fixed_Model = newDict;
}
}
I've assumed for simplicity that newDict is not nil; amend as appropriate to handle that case.
Can you narrow down the problem?
Ie. can you compare the two Dictionaries..the original one with 19 values and the new one with 18 values?
Is there a particular entry which is not being 'removed'? That might point to a challenge with 'delete' (or the lack there of).
Alternatively, if you completely replace the content, what result do you get on fetch?
so I'm trying to overwrite/update a value saved from core data. when the back button is pressed (gets the textfield data and then overwrites the data using that). But it just keeps adding new data in. Here's my code in the back button:
The IF statement is just checking what the index is so it knows which view controller to go back to. goBackMVC just takes it back to a certain view controller.
- (IBAction)btnBack:(UIBarButtonItem *)sender {
if (self.viewControllerIndex == 3) {
NSLog(#"test");
[self saveDataMethod];
[self goBackMVC];
[self.navigationController popViewControllerAnimated:YES];
}
saveDataMethod:
- (void) saveDataMethod {
NSManagedObjectContext *context = [self managedObjectContext];
// Create a new managed object
FavouriteItem *favouriteItem = [NSEntityDescription insertNewObjectForEntityForName:#"FavouriteEntity" inManagedObjectContext:context];
favouriteItem.webName = self.txtName.text;
favouriteItem.webURL = self.txtURL.text;
favouriteItem.imageURL = self.txtImageURL.text;
NSLog(#"favouriteItem.webName %#", favouriteItem.webName);
NSError *error = nil;
// Save the object to persistent store
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
}
My question is how can I overwrite the data instead of just adding it? Thanks.
edit: I've searched around and a lot of solutions have arrays, but I'm not allowed to use arrays
This is because you insert a new entity to your core data :
FavouriteItem *favouriteItem = [NSEntityDescription insertNewObjectForEntityForName:#"FavouriteEntity" inManagedObjectContext:context];
Instead fetch the required entity :
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:#"Favorits" inManagedObjectContext:context]];
To get the required entity create an NSPredicate instance to filter the required entity (in case you have more than one) and use it in your request :
NSPredicate *filterPredicate = [NSPredicate predicateWithFormat:<Your filter string>];
[fetchRequest setPredicate:filterPredicate];
NSError *error = nil;
NSArray* entities = [context executeFetchRequest:fetchRequest error:&error];
if ([entities count] == 1) {
// Get the entity and update necessary fields and save in context
}
I have a method to create managed objects (IntersectionObject) each with three properties. These three properties are managed objects themselves.
PropertyObject1, PropertyObject2, and PropertyObject3 each has about 20 different possibilities.
An IntersectionObject is essentially a combination of a particular PropertyObject1, PropertyObject2, and PropertyObject3.
There are about 1200 IntersectionObjects and to create them I am using a fetch request to retrieve and set the the correct PropertyObject:
- (PropertyObject1 *)fetchedPropertyObject1FromID: (NSNumber *)propertyObjectID {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"PropertyObject1" inManagedObjectContext:[self managedObjectContext]];
[fetchRequest setEntity:entity];
NSError *error = nil;
NSArray *fetchedObjects = [[self managedObjectContext] executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
NSLog(#"error fetching PropertyObject from ID, error:%#", error);
return nil;
}
for (PropertyObject1 *object in fetchedObjects) {
if (object.propertyObjectID.longValue == propertyObjectID.longValue) {
return object;
}
}
return nil;
}
I am finding that repeating this fetch three times for each of the 1200 IntersectionObjects takes about 2 seconds, and is too slow. Is there a faster way to do this?
EDIT: the accepted answer has the solution that I used in the comments below it. It turns out simply mapping the PropertyObjects to a dictionary was the simplest and quickest way to get the associated objects.
If you have the managed object id, use objectWithID: on the MOC.
If you don't, and you're going to be creating a lot of associations in a short space of time, fetch all of the managed objects from the MOC in batches (perhaps 100 items each batch, see fetchBatchSize on NSFetchRequest), create a dictionary mapping your objectID to the managed objects so you can just do a local lookup. Turn each object back into a fault as you process the batch with refreshObject:mergeChanges:.
Use a predicate to do this, also set the fetch limit to 1. This should get your result in a much more optimized fashion:
- (PropertyObject1 *)fetchedPropertyObject1FromID: (NSNumber *)objectID {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"PropertyObject1" inManagedObjectContext:[self managedObjectContext]];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"objectID == %#", objectID]];
[fetchRequest setFetchLimit:1];
NSError *error = nil;
NSArray *fetchedObjects = [[self managedObjectContext] executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
NSLog(#"error fetching PropertyObject from ID, error:%#", error);
return nil;
}
if(fetchedObjects.count > 0)
{
[return fetchedObjects objectAtIndex:0];
}
return nil;
}