Managed Object saves with old data - iphone

I am trying to add objects to a persistent store in Core Data.
When the user taps the save button I initialize a new object which is a subclass of the NSManagedObject class and in the data model.
Profile *newProfile = [[Profile alloc] initWithEntity:[NSEntityDescription entityForName:#"Profile" inManagedObjectContext:MOC] insertIntoManagedObjectContext:MOC];
[newProfile setValue:userName.text forKey:#"userName"];
[newProfile setValue:txtInstitution.text forKey:#"institution"];
I can verify in the console that the values for userName and txtInstitution are correct and what expected, and also that the object has the proper attributes. However, it seems to save the object with the same values as whatever the first object saved was. Only one profile is created at a time, and the MOC is saved after each profile is added in this way.
Also, when a table tries to populate with data from the persistent store it will create rows as though are as many objects in the store as I have created at that time, but they will all have the same values.

Are you sure you are retrieving the objects from the store correctly? This sounds like it might be an issue with the fetch request you use to get the data out of the store and/or an issue with the way you display the data.

Is there any particular reason you're not using the designated initialiser for NSManagedObjects?
- (id)initWithEntity:(NSEntityDescription *)entity insertIntoManagedObjectContext:(NSManagedObjectContext *)context
So you should use:
Profile *newProfile = [NSEntityDescription insertNewObjectForEntityForName:#"Profile" inManagedObjectContext:self.MOC];
Also make sure you are accessing your MOC via its property (self.MOC, not the ivar directly) as if you are using the templates provided by Apple you will notice the MOC is lazily loaded via its getter method.

Related

ios/core data - saving entity for a specific entity object

i got a qeustion about core data and the rules of relationships.
I have a entitie with multiple Users. The Users have a optional one-to-many relationship to a entitie called event. On my App start i create a User (I my self) and also other users and save them in CD. The Object of the User that i m, is also hold in NSUserDefaults.
So, now i created a event and want to assign it to my userobject entitie that is saved in core data. I thought to use the user object that i saved in the userdefaults and add the event to it, like here:
Event *event = (Event *)[NSEntityDescription insertNewObjectForEntityForName:#"Event" inManagedObjectContext:managedObjectContext];
//property setters
event.createdBy = userObjectFromNSUserDefaults;
Is this the right way? Will that assign the Event to that specific User (in that example me) ?
Another qeustion is:
My event class (subclass of nsmanagedobject) has also a NSSet property with add and remove methods that add/remove invitedUsers or acceptedUsers to that event. How do I use those methods right?
Any help gets a cookie :=)
About the first question - Yes, thats the way to make relationships in Core Data.
You just assign a specific object (NSManagmentObject, yes?) to a property.
The other way to day that, if it's one to many, is to do
[userObjectFromNSUserDefaults addEvent:event];
again, if its management object.
The only problem I see here, is that you save it in nsuserdefualts. That means that when you load it from there, it is not attached to you MOC, and I guess it won't work.
You need to save some id or something in the nsuserdefaults, not the object itself.
When the app loads, fetch that object from the db using that id.

Accessing managed object by objectID

I have three contexts:
masterMOC - private queue tied to the persistent store, so physical saves happen here
----mainMOC - main queue tied to the UI, child of masterMOC
-------backgroundMOC - private queue, child of mainMOC
Let's see I create an Employee object on the mainMOC, then save the mainMOC. Then I save the masterMOC (which writes to disk).
Now, I've saved the Employee NSManagedObjectID in a variable, objectID. I want to get this Employee on the backgroundMOC. Does [backgroundMOC objectWithId:objectID] serve this purpose? Will it go to the persistent store and fetch this object using that method? Or will I have to preform a fetch request?
Your'e doing it right. They want you to pass objects between MOContexts using ID's. objectWithId will hit the persistent store and load the object in a fresh state.
The only gotcha you have to worry about is this case.
You fetch an object or create a new object in a MOContext.
You try pass the objectID to another context WITHOUT SAVING
The new MOContext wont know about the updates, and if you created a new object the objectID wouldn't be in the persistent store, so I think it returns nil or it's not defined.
There is a WWDC video from this year titled 'Core Data Best Practices' that talks about nested MOC's. But to answer your question, yes, objectWithId will travel up through the fewest number of MOC levels to find the object. So if you call [backgroundMOC objectWithId:objectID] and the object exists in the mainMOC, it will get it from the mainMOC without having to go all the way to the masterMOC or the database.

How to write custom accessors for an NSManagedObject subclass?

I have a view called Cart. It displays a table of Items. These Items need to persist, so Item subclasses NSManagedObject; values like id, price, etc. are properties whose accessors are #dynamic so that they are automagically generated.
I have another view called Favorites. It displays a table of Items, but they don't need to persist. In fact, this view changes whenever the user logs in with different credentials.
The connection between the two views is that the user can add items to his cart from his favorites. A cart can store Items from different Favorites lists. Favorites lists don't change when the item is added to the cart.
Initially, I made the model for the Favorites view be an NSArray of NSDictionary objects. When the user adds the item to his cart, I create and save the item in Core Data from the NSDictionary key-value pairs. This approach doesn't look very clean or very DRY. Wouldn't it make more sense to make the Favorites view's model be an NSArray of Items?
So now my intent is to implement the Item class so that it will represent the Core Data model (NSManagedObject), but also work with the Favorites view. Being new to Objective-C and iOS development, I really don't know how this would work or look like. It seems that I would need to override the accessors that are magically created for me, but I can't call them at compile time using a super call... Can anyone give me a rough outline of when it would know to return the NSDictionary data or the Core Data data? In the case that it's Core Data data, how do I maintain the same level of efficiency that the magically-generated accessors would have?
Even better, is there a better implementation that is just as DRY or makes more sense? Or am I trying to combine too much functionality into one class? Is the NSArray of NSDictionary objects the best way to go in this case?
You can specify a result type on your fetch request (object, objectID, count, dictionary).
Also, I would not use NSManagedObjects outside of a MOC. You should either have a separate object that you use for memory stuff, or you can use an in-memory persistent store for those objects... or, you can just create a separate MOC as a child to your main database MOC that you use for your in-memory objects.
The advantage of these approaches is that your code does not have to know whether they are backed to the disk or not.
As long as you do not save the MOC, the changes to those objects will never go to disk.
EDIT
NSFetchRequest *fetchRequest = // create the fetch request...
fetchRequest.resultType = NSDictionaryResultType;
Now, when you make the fetch, instead of getting back an array of NSManagedObject you will get back an array of NSDictionary.

NSManagedObject for temporary use, how to switch between NSObject and NSManagedObject

Im using a Core Data model for my iPhone app. I have been looking for a way to instantiate or use an Entity outside the ManagedObjectContext. (This should not be done, I know, Im also more looking for a way to not do that, but get the benefits anyway).
My challenge is that I have a view where the user can search for "Persons", all the search results are parsed and put into a Person managedObject then displayed in a list.
If the user clicks a Person from the list, then and only then would I like the Person entity to be persisted to the store, however this requires me to delete all the other results so they don't get persisted along with the desired one. Also to the best of my knowledge, if the user decides to quite the app, the store is persisted, potentially with all current search results mixed in with real user data!
Is there some way I could have a TempPerson NSObject I could use for the search list? Without, however, me having to manually pull the 45 attributes from the temp object and manually set them on the managedObject!
Sort of like:
NSManagedObject aPersonCorrectlyReturnedFromTheStore = (NSManagedObject *)tempPersonOfJustTypeNSObject
I have seen example code from Apple where they build a temporary store to facilitate undo/redo and other stuff on an object that is not yet persisted. This I feel would be overkill in my situation. I just need to display search results until the user selects a Person to persist.
Hope it is clear what Im trying to do, feeling like my Core Data vocabulary isn't quite large enough yet:)
Thanks for any suggestions.
You could create each temporary person object as an NSDictionary or NSMutableDictionary. You can then create a new Person managed object and use the fact that NSManagedObject instances are KVC compliant and use setValuesForKeysWithDictionary:.
New managed objects that are inserted are not actually persisted until you send the managed object context a save: message.
Keep track of them in a collection (set or array) -- you are probably already doing this since you are presenting the search results somehow. Then, delete (deleteObject:) them all except for the one(s) that the user selects.
The deleted managed objects will never be stored.

NSManagedObject subclass outside of managed object as a normal object

I have an entity object Country with country name and country code. It is a subclass of NSManagedObject and I am using it with core data model to store its value to a persistent store.
I have a place where the same Country object will used as a normal object i.e. I will use it to store some temporary country name.
For that I have initialized the Country as following
[NSManagedObject alloc] init]
Initialization successfully done, but I am not able to set any property to that object.
Hence I did an exploration. In that I found that, init for the NSManagedObject is not supported as per the documentation.
I don't know how to use the NSManagedObject Country with CoreData as well as a normal Object.
2nd paragraph of the NSManagedObject class documentation's overview:
A managed object is associated with an
entity description (an instance of
NSEntityDescription) that provides
metadata about the object (including
the name of the entity that the object
represents and the names of its
attributes and relationships) and with
a managed object context that tracks
changes to the object graph. It is
important that a managed object is
properly configured for use with Core
Data. If you instantiate a managed
object directly, you must call the
designated initializer
(initWithEntity:insertIntoManagedObjectContext:).
From the documentation of the method:
Important: This method is the
designated initializer for
NSManagedObject. You should not
initialize a managed object simply by
sending it init.
The documentation is actually very good.
You do not want to try to use an NSManagedObject outside of a viable CoreData stack. NSManagedObjects are quite explicitly designed to work within a correctly configured Core Data environment. If you need a temporary instance, you can either create an in-memory store or create one in your regular store and just don't save the changes without deleting it first.
Use initWithEntity:insertIntoManagedObjectContext: and pass nil for managed object context.