I have three entities:
Notification
PlanDate
User
Relationships:
Notification has to-one relationship with PlanDate
Notification also has to-many relationship with User
Code:
NSLog (#"Selected Object From Detail ViewDidLoad %#", managedObject);
NSManagedObject *planDateObject = ((PlanDate *)[managedObject valueForKey:#"plandate"]);
NSLog(#"planDateObject %#", planDateObject);
NSString *recipientUserName = [planDateObject valueForKey:#"recipientUserName"];
NSLog(#"recipientUserName: %#", recipientUserName);
Here is the log:
2013-08-21 12:26:50.349 Time[5018:c07] Selected Object From Detail ViewDidLoad <Notification: 0xa58ee70> (entity: Notification; id: 0xb2a5480 <x-coredata://C0FB76AD-19EB-42BA-981A-F99DD6DCF6C7-5018-0000101A36CFA3D1/Notification/p0B2ABAC1-77F3-4F46-B14D-34652F148B37> ; data: {
appType = 1;
invitationType = PlanDate;
lastmoddate = "2013-08-21 17:42:42 +0000";
"notification_id" = "0B2ABAC1-77F3-4F46-B14D-34652F148B37";
plandate = "0xa1c9350 <x-coredata://C0FB76AD-19EB-42BA-981A-F99DD6DCF6C7-5018-0000101A36CFA3D1/Notification/p1C004B2B-F1DA-4EE0-9FAC-0A89E0DBCDB7>";
users = "<relationship fault: 0xb2aa210 'users'>";
})
2013-08-21 12:26:50.350 Time[5018:c07] planDateObject <Notification: 0xb292800> (entity: Notification; id: 0xa1c9350 <x-coredata://C0FB76AD-19EB-42BA-981A-F99DD6DCF6C7-5018-0000101A36CFA3D1/Notification/p1C004B2B-F1DA-4EE0-9FAC-0A89E0DBCDB7> ; data: <fault>)
2013-08-21 12:26:53.406 Time[5018:c07] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<Notification 0xb292800> valueForUndefinedKey:]: the entity Notification is not key value coding-compliant for the key "recipientUserName".'
There is indeed an attribute "recipientUserName" with a Value. I have tried other attributes that produce the same log.
Why the error? Why is the Data shown as fault when I'm trying to access its attribute?
EDIT
The error message says that there is not actually an attribute named recipientUserName on the entity Notification. Let's run through your results to see what happened. First you do this:
NSLog (#"Selected Object From Detail ViewDidLoad %#", managedObject);
And the result is this:
2013-08-21 12:26:50.349 Time[5018:c07] Selected Object From Detail ViewDidLoad <Notification: 0xa58ee70> (entity: Notification; id: 0xb2a5480 <x-coredata://C0FB76AD-19EB-42BA-981A-F99DD6DCF6C7-5018-0000101A36CFA3D1/Notification/p0B2ABAC1-77F3-4F46-B14D-34652F148B37> ; data: {
appType = 1;
invitationType = PlanDate;
lastmoddate = "2013-08-21 17:42:42 +0000";
"notification_id" = "0B2ABAC1-77F3-4F46-B14D-34652F148B37";
plandate = "0xa1c9350 <x-coredata://C0FB76AD-19EB-42BA-981A-F99DD6DCF6C7-5018-0000101A36CFA3D1/Notification/p1C004B2B-F1DA-4EE0-9FAC-0A89E0DBCDB7>";
users = "<relationship fault: 0xb2aa210 'users'>";
})
This says that managedObject is an instance of Notification, and that Notification's attributes are:
appType
invitationType
lastmoddate
notification_id
plandate
users
The plandate attribute is actually a to-one relationship. According to the log message, the object at the other end of this relationship is another instance of Notification (as indicated by the x-coredata managed object ID representation). I'm guessing you meant this to be an instance of PlanDate, but your log message says that this isn't what you actually have there.
Next you do this:
NSManagedObject *planDateObject = ((PlanDate *)[managedObject valueForKey:#"plandate"]);
NSLog(#"planDateObject %#", planDateObject);
And the result is:
2013-08-21 12:26:50.350 Time[5018:c07] planDateObject <Notification: 0xb292800> (entity: Notification; id: 0xa1c9350 <x-coredata://C0FB76AD-19EB-42BA-981A-F99DD6DCF6C7-5018-0000101A36CFA3D1/Notification/p1C004B2B-F1DA-4EE0-9FAC-0A89E0DBCDB7> ; data: <fault>)
So if you had any doubt about what type planDateObject is, this nails it. It's most definitely an instance of the Notification entity. The typecast to PlanDate doesn't mean anything here. The fact that the data is shown as <fault> is normal here, because at this point you haven't tried to access any of its attributes.
Finally you do this:
NSString *recipientUserName = [planDateObject valueForKey:#"recipientUserName"];
You're trying to get the value of the recipientUserName attribute. But we already know that planDateObject is a Notification, and that Notification does not have an attribute with that name. So, you get an exception from trying to access a nonexistent key.
So, if your PlanDate entity has an attribute named recipientUserName, then your problem is that the plandate relationship is pointing at the wrong object. If PlanDate does not have that attribute, you have more complex problems that can't be solved from the information you've provided.
Related
I have a Core Data object called User and another one called Conversation. I added a relationship between the two. The relationship is called lastConversation.
This is how it looks like:
I also added it to the User.swift class as so:
#NSManaged public var lastConversation: Conversation?
Now i'm trying to use this property in order to predicate out from CoreData. Here is a sample of a predicate that doesn't work for me:
NSPredicate(format: "lastConversation.uid == 123")
But when I run it, it crashes and says:
SQLCore dispatchRequest: exception handling request: <NSSQLFetchRequestContext: 0x600000a5d5e0> , keypath lastConversation.uid not found in entity LPUserEntity with userInfo of (null)
Can anyone help me?
maybe someone could tell me if i am on the right way.
I have two entities:
Exercise with following attributes:
title - string ; exercise_id - int
AddedExercise with following attributes:
count - int ; added_exercise_id - int
The AddedExercise has a fetched property called link_exercise with Destination: Exercise
and predicate: exercise_id == $FETCH_SOURCE.added_exercise_id
In my code i do the following:
for(AddedExercise *e in listOfAddedEx){
[moc refreshObject:e mergeChanges:YES];
NSLog(#"%#", e.link_exercise);
}
And the log says:
Relationship fault for (), name link_exercise, isOptional 1, isTransient 1, entity AddedExercise, renamingIdentifier link_exercise, validation predicates (
), warnings (
), versionHashModifier (null)
userInfo {
}, fetchRequest (entity: Exercise; predicate: (exercise_id == $FETCH_SOURCE.added_exercise_id); sortDescriptors: ((null)); type: NSManagedObjectResultType; ) on 0x1700d8b80
So it seems like something is there, represented in a fault.
But if i try to access the "link_exercise" array. For example with:
e.link_exercise.count or e.link_exercise.lastObject
I'll get the following error:
'NSUnknownKeyException', reason: '[<_NSCoreDataTaggedObjectID 0xd000000000040002> valueForUndefinedKey:]: this class is not key value coding-compliant for the key added_exercise_id.'
Maybe someone has an idea how to solve that.
Many thanks in advance.
S.R.
-----> UPDATE 1:
I changed now the predicate to:
SELF.exercise_id=exercise_id
Now i can access the Exercise object but i get a wrong id, because
SELF.exercise_id=exercise_id should look like SELF.exercise_id=added_exercise_id
With predicate SELF.exercise_id=added_exercise_id i get the following error:
'NSInvalidArgumentException', reason: 'Unable to generate SQL for predicate (exercise_id == added_exercise_id) (problem on RHS)'
-----> UPDATE 2:
Still cannot figure out why it isn't working...
For me it seems like
SELF.exercise_id == $FETCH_SOURCE.added_exercise_id
should be the right predicate, but it doesn't work.
Maybe someone else has some suggestions...?
Or should i create a fetch request by myself (programmatically) ?
That means set up a fetch request to all "Exercise"s and give the one back where exercise_id = added_exercise_id. This is basically that, what i currently try to solve through a fetched property.
-----> UPDATE 3:
Ok i nearly have it!! One thing i forgot to mention is, that i use a multi managedObjectContext core data stack (Including a worker-, main- master-context)
masterContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
masterContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
[masterContext setPersistentStoreCoordinator: coordinator];
mainContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
mainContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
mainContext.parentContext = masterContext;
workerContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
workerContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
workerContext.parentContext = mainContext;
All my request go to the worker-context (in this case the fetched proper doesn't work)
BUT if all my requests go to the master-context the fetched property works as expected!!
So it seems like it only works with the managedObjectContext which has the persistent store.
Can somebody explain me, why this cannot work with an other managedObjectContext?
I am creating an NSManagedObject subclass (Group), set some properties/attributes and then pass it on to a different object (where it is stored in a strong property). This object takes some of the Group information and sends it to a server over an instance of GCDAsyncSocket. The server responds with some information that I then want to store as an attribute of the Group. However, by the time the server responds back and GCDAsyncSocket's delegate is called, all of the Group's attributes are set to nil.
Since I'm using UIManagedDocument for my Core Data implementation, when the auto-save kicks in, I get the following error:
Error Domain=NSCocoaErrorDomain Code=134030 "The operation couldn’t be
completed. (Cocoa error 134030.)" UserInfo=0x1f5c96f0
{NSAffectedObjectsErrorKey=(
"<Group: 0x1f5aa300> (entity: Group; id: 0x1f5c73b0 ;
data: {<entities here, nil values>})" ), NSUnderlyingException=Cannot
update object that was never inserted.}
However, I know that the objects are inserted. It did some research and found a lot of problems that were related to using two or more different managed object contexts, but that is not my problem (as the only managed object context I ever get is from the UIManagedDocument).
Some code:
#property(nonatomic, strong) Group *currentGroup;
// ....
- (void)storeGroupOnServer:(Group *)group {
self.currentGroup = group;
NSLog("%#", self.currentGroup); // correct value for name attribute
[self.currentGroup addObserver:self forKeyPath:#"name" options:NSKeyValueObservingOptionNew context:NULL];
// do some other things, unrelated to this problem
// write data to socket
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
// This method is called before the socket returns with response data
NSLog(#"%#", (Group *)object.name); // incorrect value for name attribute (nil)
NSLog(#"%#", self.currentGroup); // same as above
}
Anybody who has a clue what I'm doing wrong here?
Currently, I am developing an app to book cars. All booking related data are stored in an entity 'Bookings'. As some attributes of 'Bookings' or relationships between 'Bookings' and other enties are mandatory I decided to add all managedObjects of entity 'Bookings' to their own managedObjectContext. This context will also be stored in a separate variable to avoid losing it. This works fine unless I'll sign (enterprise store or adhoc) my app and deploy it. ARC is enabled.
Class Bookings interface
#interface Bookings : NSManagedObject {
#private
NSManagedObjectContext *mContext;
}
#end
Class Bookings implementation
#implementation Bookings {
+ (Bookings *)booking {
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:concurrencyType];
[context setPersistentStoreCoordinator:[self persistentStoreCoordinator]];
Bookings *object = (Bookings*)[[NSManagedObject alloc] initWithEntity:[self entityForName:pName] insertIntoMarenagedObjectContext:context];
[object setSomeReservationData:...];
...
// here I store the context in an ivar of my booking object
[object->mContext = context];
return object;
}
}
At this state the Booking object will not be saved!
Class BookingsVC
Bookings *booking = [Bookings booking];
NSLog(#"Context: %#", [booking managedObjectContext]);
Nothing saved or altered but context is null.
Console output on device (adhoc signed and deployed via iPhone-Configurator or Testflight)
... Context: (null)
Console output on simulator or device (adhoc signed but installed via Xcode)
... Context: <NSManagedObjectContext: 0x893c520>
So why does an unsaved managedObject lose its managedObjectContext and how can this be avoided? Is it a bug or the expected behavior?
Your context is nullified at the end of your function. see here
Your object is disowned by the context making all its properties null, in debug mode there exists an autorelease pool keeping the context from being deallocated.
I'm trying to implement a getter on one of my db classes. But when I execute the following line of code, where "obj" is an NSManagedObject:
return [obj valueForKey:#"activationData"];
I get the following NSUnknownKeyException:
'[ valueForUndefinedKey:]: the entity Blueprint is not key value coding-compliant for the key "activationData".'
I just recently added a String attribute named "activationData" to my "Blueprint" entity using Xcode. But when I run the app the NSManagedObject that represents Blueprint entities does not include the new "activationData" attribute, which apparently is the cause of the crash.
The NSManagedObject looks like this, but I expected it to show the new Attribute along with the createDate, name and order attributes:
<NSManagedObject: 0x5138c90> (entity: Blueprint; id: 0x513a2e0 <x-coredata://8C586BB8-B9E7-4FD7-84CB-5CE66FB221E6/Blueprint/p2> ; data: {
createDate = "2012-02-21 15:49:00 +0000";
name = "Feb 17 test";
order = 2;
})
Fyi, user1226119's answer (below) reminded me that I used the Organizer to extract the sqlite db from my device and inspect it with SQLite Manager to verify things. Sure enough there is still no new activationData field in the Blueprint table. The table looks the same as it always did.
I think I must have missed some necessary step for adding a new Attribute to an existing db Entity.
Your model has not change in your app. You must delete your old application and re-deploy your app on your device.
The solution was to update the pathForResource method call in the code that returns the NSManagedObjectModel. I had indeed created a new xcdatamodel version of the db before adding the attribute, but apparently you are supposed to refer to it using the following code, which retrieves the model your app will use.
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel != nil) {
return managedObjectModel;
}
NSString *path = [[NSBundle mainBundle] pathForResource:#"MyDB Version5" ofType:#"mom" inDirectory:#"ASSIST.momd"];
NSURL *momURL = [NSURL fileURLWithPath:path];
managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:momURL];
return managedObjectModel;
}
I had to put the new database version's name ("MyDB Version5") as the pathForResource parameter. Previously it was "MyDB Version5".