I am performing an NSOperation on a background thread that imports data into Core Data. I do this by first creating a record of the import ('Import') and then import an object that relates to the import record. If I save the managed object context, the next attempt to link an imported object to the import record will fail:
Illegal attempt to establish a relationship 'import' between objects in different contexts (source = <NSManagedObject: 0x1067bb730> (entity: Genre; id: 0x1053330c0 <x-coredata:///Genre/tC6A85CFE-3D0A-4E29-9186-4FD46104AEBC60> ; data: {
import = nil;
name = Polka;
}) , destination = <NSManagedObject: 0x106736170> (entity: Import; id: 0x103b571e0 <x-coredata://440D80CF-7C56-4B6F-9778-990032A76B8B/Import/p1> ; data: <fault>))
Here is the boiled-down code. I modified the code slightly to demonstrate the effect by adding a superfluous save; normally there'd be no reason to have one there.
NSError *writeError = nil;
TNAppDelegate *del = (TNAppDelegate *)[[NSApplication sharedApplication] delegate];
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
[moc setPersistentStoreCoordinator:[del persistentStoreCoordinator]];
[moc setUndoManager:nil];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:#selector(mergeChanges:)
name:NSManagedObjectContextDidSaveNotification
object:moc];
// create import instance
NSManagedObject *import = [NSEntityDescription insertNewObjectForEntityForName:#"Import" inManagedObjectContext:moc];
[import setValue:[NSDate date] forKey:#"start"];
[moc save:&writeError];
[moc reset];
NSString *newGenre = [songDictItem objectForKey:#"Genre"];
NSManagedObject *newGenreObject = [NSEntityDescription insertNewObjectForEntityForName:#"Genre" inManagedObjectContext:moc];
[newGenreObject setValue:newGenre forKey:#"name"];
[newGenreObject setValue:import forKey:#"import"]; // BOOM!
UPDATE: By request, I am providing the code for mergeChanges:. It is found in the NSOperation. I have tried a number of variations on saving changes to the main MOC, but they've all ended the same way.
- (void)mergeChanges:(NSNotification*)notification
{
TNAppDelegate *del = (TNAppDelegate *)[[NSApplication sharedApplication] delegate];
if ([notification object] == [del managedObjectContext]) return;
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:#selector(mergeChanges:) withObject:notification waitUntilDone:YES];
return;
}
[[del managedObjectContext] mergeChangesFromContextDidSaveNotification:notification];
}
To this day I never figured out exactly what was going on. In the end I rebooted my project and designed it like this tutorial from the ground up. I had used it in the past for reference but somehow it took a full adoption of their code to work.
Related
how does my fetchedResultsController method look like, if I want to fetch all my attributes for an entity from core data? I only know and understand how to fetch data for a tableView and I think that is where all my confusion is coming from.
Here is my Core-Data setup:
I'm trying to fill an array with all the Attributes my Setting entity has and the show those values via NSLog output in my debug console.
Here is what I changed so far:
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObject *newEntry = [NSEntityDescription insertNewObjectForEntityForName:#"Setting" inManagedObjectContext:context];
//NSManagedObject *newSetting = [NSEntityDescription insertNewObjectForEntityForName:#"Setting" inManagedObjectContext:context];
[newEntry setValue: #"StudiSoft" forKey:#"settingName"];
if (_overrideSysTimeSwitch.on) {
[newEntry setValue: #YES forKey:#"settingSysTimeOverride"];
//editSetting.settingSysTimeOverride = #YES;
NSLog(#"IF A");
} else {
//[newEntry setValue: #NO forKey:#"settingSysTimeOverride"];
//editSetting.settingSysTimeOverride = #NO;
NSLog(#"IF B");
}
if (_timeFormatSwitch.on) {
//[newEntry setValue: #YES forKey:#"settingTimeFormat"];
//editSetting.settingTimeFormat = #YES;
NSLog(#"IF C");
} else {
//[newEntry setValue: #NO forKey:#"settingTimeFormat"];
//editSetting.settingTimeFormat = #NO;
NSLog(#"IF D");
}
[self.settingsArray addObject:#"StudiSoft"];
NSError *error;
[context save:&error];
I'm using this code-snipped that and I'm able to modify the core data content.
However, every time I run this code, it of course adds a new object.
I've been looking for a way to update existing Attributes in my Entity, or modify them, but I could NOT find them.
Anyhow this is a good step into the right direction.
I created a completely new project, with just one view, once I have it working on the main view I'm going to experiment with segues....
But for now, how would I update or change existing attributes?
Thanks guys!!
This is my editSave Method to store some data in core data:
- (IBAction)editSave:(UIBarButtonItem *)sender
{
if ([_editSaveButton.title isEqualToString:#"Edit"])
{
[self setTitle:#"Edit Settings"];
//self.title = #"Edit Settings";
_overrideSysTimeSwitch.userInteractionEnabled = YES;
_timeFormatSwitch.userInteractionEnabled = YES;
_editSaveButton.title = #"Save";
} else if ([_editSaveButton.title isEqualToString:#"Save"])
{
[self setTitle:#"Settings"];
//self.title = #"Settings";
_overrideSysTimeSwitch.userInteractionEnabled = NO;
_timeFormatSwitch.userInteractionEnabled = NO;
_editSaveButton.title = #"Edit";
// #############################################################
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
//NSManagedObject *newEntry = [NSEntityDescription insertNewObjectForEntityForName:#"Setting" inManagedObjectContext:context];
//[newEntry setValue: #"StudiSoft" forKey:#"settingName"];
/*NSString *firstName = [anEmployee firstName];
Employee *manager = anEmployee.manager;
Setting *newSetting = [NSString #"Test"];
[newSetting setValue:#"Stig" forKey:#"settingName"];
[aDepartment setValue:[NSNumber numberWithInteger:100000] forKeyPath:#"manager.salary"];*/
//editSetting.settingName = #"Test";
if (_overrideSysTimeSwitch.on) {
//[newEntry setValue: #YES forKey:#"settingSysTimeOverride"];
editSetting.settingSysTimeOverride = #YES;
NSLog(#"IF A");
} else {
//[newEntry setValue: #NO forKey:#"settingSysTimeOverride"];
editSetting.settingSysTimeOverride = #NO;
NSLog(#"IF B");
}
if (_timeFormatSwitch.on) {
//[newEntry setValue: #YES forKey:#"settingTimeFormat"];
editSetting.settingTimeFormat = #YES;
NSLog(#"IF C");
} else {
//[newEntry setValue: #NO forKey:#"settingTimeFormat"];
editSetting.settingTimeFormat = #NO;
NSLog(#"IF D");
}
//[self.settingsArray addObject:#"StudiSoft"];
NSError *error = nil;
//if ([self.managedObjectContext hasChanges]) {
//NSLog(#"SAVE & DISMISS conetx has changed");
if (![context save:&error]) { // save failed
NSLog(#"Save failed: %#", [error localizedDescription]);
} else { // save succeeded
NSLog(#"Save Succeeded");
}
//}
//[self.tableView reloadData];
// #############################################################
}
}
Debug Output:
2014-06-10 19:09:29.881 SettingsCoreData[508:60b] Entry #5: <Setting: 0x8f983e0> (entity: Setting; id: 0x8f97030 <x-coredata://FA78AB86-3225-4B1E-97DD-3F31F5323A18/Setting/p6> ; data: {
settingName = StudiSoft;
settingSysTimeOverride = 0;
settingTimeFormat = 0;
})
2014-06-10 19:09:29.883 SettingsCoreData[508:60b] Entry #6: <Setting: 0x8f98430> (entity: Setting; id: 0x8f97040 <x-coredata://FA78AB86-3225-4B1E-97DD-3F31F5323A18/Setting/p7> ; data: {
settingName = StudiSoft;
settingSysTimeOverride = 1;
settingTimeFormat = 1;
})
Now I should be able to use something like this in my viewDidLoad, right?
if (editSetting.settingSysTimeOverride.boolValue == 0) {
_overrideSysTimeSwitch.on = NO;
} else {
_overrideSysTimeSwitch.on = YES;
}
But it doesn't work as I thought it will :-(
Next you need to call -performFetch: on the NSFetchedResultsController. Make sure you check the response and handle the error if the response is NO.
From there your NSFetchedResultsController is populated and ready to be used. You can then grab individual elements via -objectAtIndex: or you can grab them all with -fetchedObjects.
I would suggest just reviewing the documentation on the methods that are available as it has pretty strong and clear documentation.
Update
If you are not receiving any data then break it down. Take the NSFetchRequest that you created and call -executeFetchRequest:error: against your NSManagedObjectContext and see if you get any data back.
If you do then there is something wrong with your handling of the NSFetchedResultsController.
If you don't then there is something wrong with your NSFetchRequest or you don't have any data in your store.
Update
Sounds like you need to read a book on how Core Data works.
A NSFetchRequest is a query against Core Data so that objects can be returned from the store. You can pass a NSFetchRequest to a NSFetchedResultsController so that the NSFetchedResultsController can monitor the store for changes and let your view controller know when those changes occur.
A NSFetchRequest can also be executed directly against the NSManagedObjectContext and you can retrieve the results directly. You do that by calling -executeFetchRequest:error: against your NSManagedObjectContext and getting a NSArray back. You can then check that NSArray to see if you get any results.
If you do not understand that paragraph then you need to take a step back and read the tutorials on Core Data and/or read a book on Core Data. I can recommend an excellent book on the subject ;-)
I am having issues trying to get my CoreData to save, I have used CoreData before and don't normally run in to these issues. Can someone tell me what is wrong with the following code:
MapEntity *mapEntity = [_fetchedResultsController objectAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
NSMutableSet *set = (NSMutableSet *)mapEntity.points;
[set removeObject:self.selectedPoint];
self.selectedPoint = nil;
[[Singleton sharedSingleton] saveContext];
To initialise my fetched results controlled I use the following:
NSEntityDescription *entity = [NSEntityDescription entityForName:#"MapEntity" inManagedObjectContext:[[Singleton sharedSingleton] managedObjectContext]];
So the entity returned should definitely be in the singletons manabged object context. The code for saveContext is below:
- (void)saveContext
{
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
NSLog(#"Unable to save context");
}
}
}
If I check the mapEntity.points after the removal of the object I can see the object has been removed. The object doesn't re-appear until I relaunch the app, so it must be a persistance issue. Can anyone figure out what's wrong with my code as I am completely baffled.
I have managed to fix the issue, seems it lied within the way I was deleting objects. Instead I am now using the set deletion functions created by CoreData, code below for anyone else with the same issues:
MapEntity *mapEntity = [_fetchedResultsController objectAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
NSSet *removeSet = [NSSet setWithObject:self.selectedPoint];
[mapEntity removePoints:removeSet];
self.selectedPoint = nil;
[[Singleton sharedSingleton] saveContext];
I am trying to save a one-to-many relation in core data. There is a user decision involved to determine whether the new child list object needs to be attached to a new parent object. In the other case an existing database entry is used as a parent object. Under certain circumstances after saving, the app crashes.
FINAL EDIT: Sorry if you mind me keeping all of the edits, I still will. The process of enlightenment was quite convoluted. After all I started out thinking it was a data conflict... Thanks again to Tom, who helped point me in the right direction: I am still using a relation for sorting and grouping core data entities with an NSFetchedResultsController. I have written a valid compare: method for my entity class now and so far from what I can see it is working. I am about to write an answer for my question. I will still be very grateful for any information or warnings from you concerning this!
EDIT 3: The save procedure and the user alert seem to be incidental to the problem. I have zoomed in on the NSFetchedResultsController now and on the fact that I am using a relation ('examination') as sectionNameKeyPath. I will now try to write a compare: method in a category to my Examination entity class. If that does not work either, I will have to write a comparable value into my Image entity class in addition to the relation and use that for sections. Are y'all agreed?
EDIT 1: The crash only occurs after the user has been asked whether she wants a new examination and has answered YES. The same method is also entered when there was no user prompt (when the creation of a new examination has been decided by facts (no examination existing = YES, existing examination not timed-out = NO). In these cases the error does NOT occur. It must be that the view finishes loading while the alert view is open and then the collection view and its NSFetchedResultsController join the fun.
EDIT 2: Thanks to Tom, here is the call stack. I did not think it was relevant, but the view controller displays images in a collection view with sections of images per examination descending. So both the section key and the sort descriptor of the NSFetchedResultsController are using the examination after the MOCs change notification is sent. It is not the save that crashes my app: it is the NSSortDescriptor (or, to be fair, my way to use all of this).
The code for the NSFetchedResultsController:
#pragma mark - NSFetchedResultsController
- (NSFetchedResultsController *)fetchedResultsController
{
if (m_fetchedResultsController != nil) {
return m_fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:NSStringFromClass([Image class]) inManagedObjectContext:[[HLSModelManager currentModelManager] managedObjectContext]];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
// Edit the sort key, identical sort to section key path must be first criterion
NSSortDescriptor *examinationSortDescriptor = [[NSSortDescriptor alloc] initWithKey:kexaminationSortDescriptor ascending:NO];
NSSortDescriptor *editDateSortDescriptor = [[NSSortDescriptor alloc] initWithKey:keditDateSortDescriptor ascending:NO];
NSArray *sortDescriptors =[[NSArray alloc] initWithObjects:examinationSortDescriptor, editDateSortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[[HLSModelManager currentModelManager] managedObjectContext] sectionNameKeyPath:kSectionNameKeyPath cacheName:NSStringFromClass([Image class])];
aFetchedResultsController.delegate = self;
m_fetchedResultsController = aFetchedResultsController;
NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error]) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
HLSLoggerFatal(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return m_fetchedResultsController;
}
#pragma mark - NSFetchedResultsControllerDelegate - optional
/* Asks the delegate to return the corresponding section index entry for a given section name. Does not enable NSFetchedResultsController change tracking.
If this method isn't implemented by the delegate, the default implementation returns the capitalized first letter of the section name (seee NSFetchedResultsController sectionIndexTitleForSectionName:)
Only needed if a section index is used.
*/
- (NSString *)controller:(NSFetchedResultsController *)controller sectionIndexTitleForSectionName:(NSString *)sectionName
{
return sectionName;
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
// In the simplest, most efficient, case, reload the table view.
[[self collectionView] reloadData];
}
/* THE OTHER DELEGATE METHODS ARE ONLY FOR UITableView! */
The code for saving examination (existing or new) and the new image:
-(BOOL)saveNewImage
{
BOOL done = NO;
// remove observer for notification after alert
[[NSNotificationCenter defaultCenter] removeObserver:self name:kExaminationTimedoutAlertDone object:nil];
Examination * currentExamination = [self getCurrentExamination];
if ([self userWantsNewExamination] == YES)
{ // if an examination was found
if (currentExamination != nil)
{ // if the found examination is not closed yet
if ([currentExamination endDate] == nil)
{ // close examination & save!
[currentExamination closeExamination];
NSError *savingError = nil;
[HLSModelManager saveCurrentModelContext:(&savingError)];
if (savingError != nil)
{
HLSLoggerFatal(#"Failed to save old, closed examination: %#, %#", savingError, [savingError userInfo]);
return NO;
}
}
}
currentExamination = nil;
}
// the examination to be saved, either new or old
Examination * theExamination = nil;
// now, whether user wants new examination or no current examination was found - new examination will be created
if (currentExamination == nil)
{
// create new examination
theExamination = [Examination insert];
if (theExamination == nil)
{
HLSLoggerFatal(#"Failed to create new examination object.");
currentExamination = nil;
return NO;
}
// set new examinations data
[theExamination setStartDate: [NSDate date]];
}
else
{
theExamination = currentExamination;
}
if (theExamination == nil)
{ // no image without examination!
HLSLoggerFatal(#"No valid examination object.");
return NO;
}
Image *newImage = [Image insert];
if (newImage != nil)
{
// get users last name from app delegate
AppDelegate * myAppDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate];
// set image data
[newImage setEditUser: [[myAppDelegate user] lastName]];
[newImage setEditDate: [NSDate date]];
[newImage setExamination: theExamination];
[newImage setImage: [self stillImage]];
[newImage createImageThumbnail];
// update edit data
[theExamination setEditUser: [[myAppDelegate user] lastName]];
[theExamination setEditDate: [NSDate date]];
// unnecessary! CoreData does it automatically! [theExamination addImagesObject:newImage];
//! Important: save all changes in one go!
NSError *savingError = nil;
[HLSModelManager saveCurrentModelContext:(&savingError)];
if (savingError != nil)
{
HLSLoggerFatal(#"Failed to save new image + the examination: %#, %#", savingError, [savingError userInfo]);
}
else
{
// reload data into table view
[[self collectionView] reloadData];
return YES;
}
}
else
{
HLSLoggerFatal(#"Failed to create new image object.");
return NO;
}
return done;
}
The error:
2013-05-22 17:03:48.803 MyApp[11410:907] -[Examination compare:]: unrecognized selector sent to instance 0x1e5e73b0
2013-05-22 17:03:48.809 MyApp[11410:907] CoreData: error: Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. -[Examination compare:]: unrecognized selector sent to instance 0x1e5e73b0 with userInfo (null)
2013-05-22 17:03:48.828 MyApp[11410:907] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Examination compare:]: unrecognized selector sent to instance 0x1e5e73b0'
And here are the entity class files, too:
//
// Examination.h
// MyApp
//
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#class Image;
#interface Examination : NSManagedObject
#property (nonatomic, retain) NSDate * editDate;
#property (nonatomic, retain) NSString * editUser;
#property (nonatomic, retain) NSDate * endDate;
#property (nonatomic, retain) NSDate * startDate;
#property (nonatomic, retain) NSSet *images;
#end
#interface Examination (CoreDataGeneratedAccessors)
- (void)addImagesObject:(Image *)value;
- (void)removeImagesObject:(Image *)value;
- (void)addImages:(NSSet *)values;
- (void)removeImages:(NSSet *)values;
#end
//
// Examination.m
// MyApp
//
#import "Examination.h"
#import "Image.h"
#implementation Examination
#dynamic editDate;
#dynamic editUser;
#dynamic endDate;
#dynamic startDate;
#dynamic images;
#end
This error had nothing to do with the saving of data to the MOC.
Because the saving of the new image data is triggered in the prepareForSegue of the previous view controller and the user alert gives the next view controller the time to finish loading, also creating the NSFetchedResultsController and its connection to its delegate, the exception was raised in the temporary context of the save to the MOC and only after the user alert.
The NSFetchedResultsController had started listening for changes of the MOC only in this case. It seems that if it gets alerted to an MOC change it will fetch only the changes and only then it needs to compare the new data with the existing data. Further information on this would be very welcome!
Then, because I had set a sort descriptor (and also the sectionNameKeyPath) to a relation and not provided the means to sort the entity objects in my core data entity class, the NSFetchedResultsController could not continue. Looking back it seems all so easy and natural, I really become suspicious of the simplicity of my solution...
I find it interesting that it could fetch the initial data in one go, when no change interfered. After all it was using the same NSSortDescriptor. Any ideas?
This is my solution:
//
// MyCategoryExamination.m
// MyApp
//
#import "MyCategoryExamination.h"
#implementation Examination (MyCategoryExamination)
- (NSComparisonResult)compare:(Examination *)anotherExamination;
{
return [[self startDate] compare:[anotherExamination startDate]];
}
#end
Please tell me if there is something wrong with this.
I need to use some core data managed objects in an NSOperation. The problem is that core data is not thread safe and apparently the object can't be loaded from the new thread. Does anybody know a good tutorial for this? I need the object read only... so the thread will not modify them in any way. Some other, unrelated entities may be added on the main thread while these objects are used in the background, but the background entities don't need to be modified at all..
Hmm seemed I fixed the background running issue, but now the problem is nothing is returned to the delegate... Why? In the thred if I nslog the results are all shown but that call to the delegate never happens
This is the code:
-(void)evaluateFormula:(Formula *)frm runNo:(NSUInteger)runCount{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue setMaxConcurrentOperationCount:2];
NSManagedObjectID *formulaId = frm.objectID;
for (int i = 0; i < runCount; i++) {
NSInvocationOperation * op = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(runFormula:) object:formulaId];
[queue addOperation:op];
}
}
-(void)runFormula:(NSManagedObjectID *)fId {
NSManagedObjectContext *thredContext =[[NSManagedObjectContext alloc] init];
NSPersistentStoreCoordinator *coord = (NSPersistentStoreCoordinator *)[(PSAppDelegate *)[[UIApplication sharedApplication] delegate] persistentStoreCoordinator];
[thredContext setPersistentStoreCoordinator:coord];
Formula *f = (Formula *)[thredContext objectWithID:fId];
NSDictionary *vars = [self evaluateVariables:[f.hasVariables allObjects]];
NSMutableString *formula = [NSMutableString stringWithString:f.formula];
for (NSString *var in [vars allKeys]) {
NSNumber *value =[vars objectForKey:var];
[formula replaceOccurrencesOfString:var withString:[value stringValue] options:NSCaseInsensitiveSearch range:NSMakeRange(0, [formula length])];
}
//parse formula
NSNumber *result = [formula numberByEvaluatingString];
// NSLog(#" formula %# result : %d",formula,[result intValue]);
//aggregate results
[self performSelectorOnMainThread:#selector(aggregate:) withObject:result waitUntilDone:YES]; // the delegate doesn't get called ...
}
-(void)aggregate:(NSNumber *)res {
[self.delegate didReceiveResult:res];
}
The code bellow add to Core data issues, but after it added, I can't save with error (multiply validation error occured)
MySQLIXC *ixcDatabase = [[MySQLIXC alloc] init];
NSArray *destinationsForSaleList = [ixcDatabase destinationsForSaleList:carrier];
NSFetchRequest *request1 = [[[NSFetchRequest alloc] init] autorelease];
[request1 setEntity:[NSEntityDescription entityForName:#"DestinationsList"
inManagedObjectContext:managedObjectContext]];
for (NSDictionary *destinationsForSale in destinationsForSaleList) {
NSManagedObject *object1 = [NSEntityDescription
insertNewObjectForEntityForName:#"DestinationsList"
inManagedObjectContext:managedObjectContext];
NSLog(#"Moc: %#",managedObjectContext);
[object1 setValue:#"y" forKey:#"weAreSoldIt"];
// changeDate
NSString *chdate = [destinationsForSale objectForKey:#"chdate"];
NSDateFormatter *changeDate = [[[NSDateFormatter alloc] init] autorelease];
[object1 setValue:[changeDate dateFromString:chdate] forKey:#"changeDate"];
NSLog(#"Carrier :%# Destination name:%#",carrier, destinationsForSale);
//Country
[object1 setValue:[destinationsForSale objectForKey:#"country"] forKey:#"country"];
//rate
NSNumberFormatter *rate = [[[NSNumberFormatter alloc]init ]autorelease];
[object1 setValue:[rate numberFromString:[destinationsForSale objectForKey:#"price"]] forKey:#"rate"];
Unfortunately I can't fix a bug by the way which u propose bellow.
Bcs Entity DestinationList must have relations with Entity Carriers by project understanding.
That is how I try to fix it:
[objectDestinationList setValue:objectCarrier forKey:#"carrier"];
I was send to method my carrier object as object, but it doesn't work.
In this case, I don't know how is a way to fix it around. Bcs I see error, but don't see case why error is start.
Do u know a simple code to correct add relationships to Entity? All what I catch around internet is a core data book ,my Marcus Zarra and his very hard to understanding example. His showing a complex solution, I can understand it, but using programming style which not very easy for me at this moment (according my one month experience in cocoa programming ;)
Here is additional information: How I create Carrier instance. I have managedObjectContext, which I receive to class from AppDelegate.
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:[NSEntityDescription entityForName:#"Carrier"
inManagedObjectContext:managedObjectContext]];
NSManagedObject *carrier = [managedObjectContext executeFetchRequest:request error:&error]
by the same way I prepare NSManagedObject for DestinationsList Entity.
After that I add all values to NSManagedObject for destinationsList, I have to make relationship between Carrer NSManagedObject and destinationsList. In this case I have trouble. Bellow is how I try to update relationship for Carrier entity:
NSSet *newDestSet = [NSSet setWithObjects:objectDestination,nil];
[objectCarrier setValue:newDestSet forKey:#"destinationsList"];
finally I have 2010-11-03 21:22:56.968 snow[20301:a0f] -[NSCFArray initialize]: unrecognized selector sent to instance 0x1c44e40
Bellow is my class interface deescription:
#interface InitUpdateIXC : NSObject {
NSInteger destinationType;
}
-(void) updateCarrierList:(NSManagedObjectContext *)managedObjectContext;
-(void)updateDestinationList:(NSManagedObjectContext *)managedObjectContext
forCarrier:(NSString *)carrierName
forCarrierObject:(NSManagedObject *)objectCarrier
destinationType:(NSInteger)destinationType;
#end
Yep, bellow in answer present correct model, but some different is here.
At first, i don't have separate class for Entity as u present in you model. My current class is just NSManagedObject
In second, relationship "carrier" is non-optional for Entity DestinationsList.
SOLUTION AND ERROR DESCRIPTION:
In case of trouble, what happened with my code:
When i try to add setValue forKey with back relationship from DestinationsList to Carrier, i forget that NSManagmentObject return every time array, not just object.
This is a reason why i receive error about array init problem.
Solution is not sent Carrier object to method, bcs for me was too hard to extract from array correct object without key value. I was using a predicate access to extract object to array and lastObject function to extract correct object from array. After that i set accroding value and everything working fine.
A solution not look like cocoa-style, so better way is refactor it in future, any suggestion wellcome.
Here is appropriate code:
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:[NSEntityDescription entityForName:#"Carrier"
inManagedObjectContext:managedObjectContext]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name =%#",carrierName];
[request setPredicate:predicate];
NSError *error = nil;
NSArray *currentCarriers = [managedObjectContext executeFetchRequest:request error:&error];
[objectDestination setValue:[currentCarriers lastObject] forKey:#"carrier"];
Try adding something like this for you 'save'
NSError *error = nil;
if (![managedObjectContext save:&error])
{
// Handle the error.
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]);
}
}
At least, then you can see what the multiple errors are. If you post those, someone may be able to offer more help.
One thought, though, is that there is something buggy about your data model - like non-optional attribute with no value, etc.
If you create NSManagedObject subclassed Carrier and DestinationsList, then in Carrier.h you should have some method declarations like this. (Assuming that Carrier to-many DestinationsList is called 'destinationsLists'.)
#interface Carrier (CoreDataGeneratedAccessors)
- (void)addDestinationsListsObject:(Run *)destinationsList;
- (void)removeDestinationsListsObject:(Run *)destinationsList;
- (void)addDestinationsLists:(NSSet *)destinationsLists;
- (void)removeDestinationsLists:(NSSet *)destinationsLists;
#end
Once these are declared, you should be able to add a DestinationsList to a Carrier with a line like this:
[myCarrier addDestinationsListsObject:myDestinationsList];
Not seeing your full data model, it is difficult to know what is happening and what would help fix it.
Do you have something like this for your model definition?