Thanks Pranav!
How about the updating my NSManagedObject? That's my biggest problem right now.
Brian,
Just wanted to check if you have tried using the onPreSave()/onPostSave() collection hooks for this purpose? So, your app would call a save on the Person (also sending the Notes data along with it). This would first save the Person entity and then call the Person.onPostSave() collection hook. In this code, then you can update the Notes collection with the relevant notes.
In case you are saving the Notes directly and passing the person name to it, you could also implement Notes.OnPreSave() logic and in it - query the Person collection for the person name and find out the person.id, that way you will also persist the person's id in the Notes collection.
I hope I have understood your usecase correctly. If not, please feed me more details. Also let me know if you see any change moving to NSObject.
I will continue reviewing the code in more details and let you know if I have some more comments.
Thanks,
Pranav
Kinvey Support
Would it work better if for saving, do NSManagedObject to NSObject to Kinvey. Then for updating, Kinvey to NSObject to NSManagedObject? I would think this would mitigate any problems that happen for updating because it seems like the Kinvey code is having trouble updating the relational NSManagedObjects. The app needs to be able to persist core data. So using just migrating to Kinvey is not an option.
@Pranav any luck?
For http://devcenter.kinvey.com/ios/guides/troubleshooting#KeyValueCodingCompliantcrashes, if I unmap Notes from Person in hostToKinveyPropertyMapping, wouldn't that mess up the saving part of it?
For http://www.kinvey.com/how-to-model-data-relationships-in-your-kinvey-backend/, it doesn't show me the code snippet and it gives me {gist:1929275.js?file=DeweyREST.txt}.
Saving
KCSLinkedAppdataStore* store = [KCSLinkedAppdataStore storeWithCollection:[KCSCollection collectionFromString:@"Person" ofClass:[MOPerson class]] options:nil]; if (!person.thumbnailId) { NSData* data = person.thumbnail; [KCSFileStore uploadData:data options:nil completionBlock:^(KCSFile *uploadInfo, NSError *error) { if (error) { NSLog(@"Upload image failed: %@", [error localizedDescription]); person.synced = [NSNumber numberWithBool:NO]; } else { person.thumbnailId = [uploadInfo fileId]; person.synced = [NSNumber numberWithBool:YES]; [store saveObject:person withCompletionBlock:^(NSArray *objects, NSError *error) { if (error) { NSLog(@"Saved Failed: %@", [error localizedDescription]); person.synced = [NSNumber numberWithBool:NO]; } else { NSLog(@"Saved Success"); } NSError* errorContext; [defaultManagedObjectContext() save:&errorContext]; } withProgressBlock:nil]; } } progressBlock:nil]; } else { [store saveObject:person withCompletionBlock:^(NSArray *objects, NSError *error) { if (error) { NSLog(@"Saved Failed: %@", [error localizedDescription]); person.synced = [NSNumber numberWithBool:NO]; } else { NSLog(@"Saved Success"); } NSError* errorContext; [defaultManagedObjectContext() save:&errorContext]; } withProgressBlock:nil]; }
Fetching
KCSLinkedAppdataStore* store = [KCSLinkedAppdataStore storeWithCollection:[KCSCollection collectionFromString:@"Person" ofClass:[MOPerson class]] options:nil]; // Load people from the cloud [store queryWithQuery:[KCSQuery query] withCompletionBlock:^(NSArray *objects, NSError *error) { if (error) { NSLog(@"An error occurred on query: %@", error); } else { NSLog(@"Get all people success"); for (MOPerson *person in objects) { if (person.thumbnailId) { [KCSFileStore downloadData:person.thumbnailId completionBlock:^(NSArray *downloadedResources, NSError *error) { if (error == nil) { KCSFile* file = downloadedResources[0]; person.thumbnail = file.data; } else { NSLog(@"Got an error: %@", error); } } progressBlock:nil]; } } } } withProgressBlock:nil];
MOPerson.h and MONotes.h
// MOPerson.h #import <Foundation/Foundation.h> #import <CoreData/CoreData.h> #import <KinveyKit/KinveyKit.h> #import "ModelUtil.h" @class MONotes; NS_ASSUME_NONNULL_BEGIN @interface MOPerson : NSManagedObject <KCSPersistable> @end NS_ASSUME_NONNULL_END #import "MOPerson+CoreDataProperties.h" //MONotes.h #import <Foundation/Foundation.h> #import <CoreData/CoreData.h> #import <KinveyKit/KinveyKit.h> @class MOPerson; NS_ASSUME_NONNULL_BEGIN @interface MONotes : NSManagedObject <KCSPersistable> @end NS_ASSUME_NONNULL_END #import "MONotes+CoreDataProperties.h"
Thanks,
Pranav
Kinvey Support
Update: Loading and querying using KCSLinkedAppdataStore gives me this error, CoreData: error: Failed to call designated initializer on NSManagedObject class. It will also call
+ (id)kinveyDesignatedInitializer:(NSDictionary *)jsonDocument
in Person.m and give me error, Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<MONotes 0x15d7f3260> setValue:forUndefinedKey:]: the entity (null) is not key value coding-compliant for the key "dateAdded".'
This only happens when the there are relational data (Notes add to Person). Would I have to use a pre/post hook on the Person Collection so that it doesn't return Notes and then load/query Notes Collection?
Answers to your questions Billy Gee:
1) Platform = Xcode/iOS
2) Kinvey SDK/Version = 1.40.7
3) Built it from scratch and trying to add Kinvey
Hello Brian,
One of our technical support engineers has been assigned to this problem. He will be asking you additional questions and providing feedback shortly. In the meantime, can you answer the following questions for us?
What platform are you using to develop your app?
What Kinvey SDK and version are you using to build your app?
Are you porting your app from another platform or are you building it from scratch using Kinvey?
Regards,
Billy Gee
I'm working with Persisting Core Data Objects to Kinvey but when I try to query/load from the KCSLinkedAppdataStore, I get "CoreData: error: Failed to call designated initializer on NSManagedObject class 'WHATEVER THE CLASS NAME IS'". Any help with this?
This should be the last thing before I get the app fully working with Kinvey.
I'm working with Persisting Core Data Objects to Kinvey but when I try to query/load from the KCSLinkedAppdataStore, I get "CoreData: error: Failed to call designated initializer on NSManagedObject class 'WHATEVER THE CLASS NAME IS'". Any help with this?
This should be the last thing before I get the app fully working with Kinvey.
Since I cannot delete the original post, I'll just add the update here. How do you save a new parent and child entity at the same time? The reason why it's giving me NSNull error is because it does not save the reference to person in the Note collection when person and note are being saved for the first time. BUT when the person is already saved and I add a note, then it saves correctly and doesn't give me a NSNull error. I now have a work around but I was wondering if there is a way to save both new entities at the same time.
Thanks guys!
I think I'm getting somewhere now but I'm getting a [NSNull managedObjectContext]: . I'm not saving anything null/nil in either entities... Does anyone have any ideas why it's giving me this error?
Brian
I have two entities, Person and Notes, that have a one to many relationship. They both are NSManagedObjects. I believe I followed everything right from the Data Store and Core Data guides.
The problem: Whenever I try and save a person, it gives me "Reference object does not have ID set". From my understanding, person.notes is what it's referring to. But this should work according to the guides.
The code:
Person.m
Notes.m
Thanks for the help!