I've got a list of elements where editing/creation is possible, I do this in a new context and save it only if the user presses save.
My problem is now that when I'd like to handle the object to an other view controller, the properties are all nil, i.e. the user presses "new element", gets the form provided, a new ManagedObject is created in a new context and properties are set. If I provide that object to another view controller, the object is fault and all properties are nil - how can I prevent this? I don't like to save and delete it if the user presses cancel, I would prefer creation/editing on a "scratchpad context" and save it only if the user really presses save.
The most likely scenario is that your scratchpad managed object context is deallocated, and this is wiping out the managed object. Managed objects are dependent on their context but don't retain them (to avoid retain cycles), so if the context ever disappears, they stop working. Nil values for properties is the most common symptom of a missing context. For possible future reference, this is also true when the managed object has already been saved, and is not still a temporary object.
Related
I have two nib files each with its own window populated by data from the same Core Data Managed Object Context (MOC) but each bound to a different array-controller. The problem is that when I delete a data object in one of the window's array-controller, it persists in the other window's array-controller even after saving the common MOC and restarting the program. To permanently remove the unwanted data object, I must remove it at each window separately. This doesn't seem the way Core Data should work. Shouldn't array controllers using the same MOC have a common source of persistent data?
For my setup of the bound array-controller, it is not enough to simply connect the window's 'delete' button to NSControllerArray's 'remove:' method. Instead, I subclass this method and specify a direct MOC delete of the target data-object as follows:
- (void)remove:(id)sender
{
[MOC deleteObject:[[self selectedObjects] lastObject]];
}
UserManagerViewController is a class that manages user objects (creates/release) for the rest of my view controllers (so that I don't create multiple User objects), I have:
var resources = Dictionary<Int, T>()
Whenever I need a resource, I do this:
let id = data["id"].intValue
self.resources[id] = User(data: data) //Create a User object and set it to the dictionary
I have other ViewControllers that "hang on" to this object when it wants to use it:
var users = [User]()
users.insert(<The pointer to resources[id]>, atIndex: 99)
//later on...
users.removeAtIndex(99) //this should release its hold
Later, when I need to release the final created object, I do this:
resources.removeValueForKey(id)
Will this method correctly ensure that the User instance simply goes away, since both its parents released it?
Yes, the user instance goes away. Swift uses automatic reference counting to manage memory. In your case, when you insert a user into a resource dict, the dict holds a reference to that user. When you later add user into users list, it also holds a reference to the user. It has two references to the same instance, therefore, when you remove user from those data structure, you have no reference to the instance, which means the user instance will be removed.
I have a menu screen that populates with data from an NSManagedObject. While this screen is up the user can enter in all sorts of values. etc.
The problem I am having is that I need to not alter the initial NSManagedObject used to populate the screen. I need a copy that the user can alter instead because if they cancel out before everything is done, then what was the original and correct information gets corrupt by impartial data.
However, I am having issues implementing any kind of copy method or process inside my NSManagedObject because all of the properties are #dynamic.
If I just 'return self' in a copyWithZone method inside the NSManagedObject, would that properly copy everything?
Why not use a category to add a copy method to your custom NSManagedObject?
If your NSManagedObject was User, then create a new category User+copy.h/m where in you would add the copy method which would simply copy all the individual fields one by one.
What you want is to make your changes to the same NSManagedObject, but in a child NSManagedObjectContext. That way, if you need to discard the changes, you can just throw the child context away without affecting your main context or object. See this question.
I am using a tableview with data from coredata using nsfetchedresultscontroller. When the view loads i make a new entity using
SomeManagedObject *someManagedObject = [NSEntityDescription insertNewObjectForEntityForName:#"SomeManagedObject" inManagedObjectContext:self.managedObjectContext];
This way the new entity appears in my tableview. Now i want this entity to be only temporary, but when i edit some object inside the tableview and save the managedObjectContext the temporary entity will also get saved and i don't want that.
Is their a way to save one object only and not everything inside de managedObjectContext?
Is their some other way to make a temporary object for my tableview.
Any help would be very welcome.
Thanks
Ton
Create the new NSManagedObject with it's alloc init and pass nil instead of the NSManagedObjectContext. Then if you later decide you want that object to be permanent then set it's context. However this will not allow you to see it in a NSFetchedResultsController because it will not be associated with the context.
A better answer can be provided if you could explain what your ultimate goal is.
No, in a managedObjectContext saving is a all or nothing. What I do not know is what happens if you set the persistent store of the managed object to nil
- (void)assignObject:(id)object toPersistentStore:(NSPersistentStore *)store
If you then save the managedObjectContext this object should not be saved. It is just a guess, but tell me if it works ;-)
For temporary managed objects, create them with a 2nd managed object context (MOC). When you are finished, simply release the MOC without performing a save.
Look at the Adding a Book code in CoreDataBooks which uses the same approach to throw away the newly added object when the user cancels.
I've created a program that uses core data and it works beautifully.
I've since attempted to move all my core data methods calls and fetch routines into a class that is self contained. My main program then instantiates that class and makes some basic method calls into that class, and the class then does all the core data stuff behind the scenes. What I'm running into, is that sometimes I'll find that when I grab a managed object from the context, I'll have a valid object, but its properties have been deallocated, and I'll cause a crash. I've played with the zombies and looked for memory leaks, and what I have gathered is it seems that the run loop is probably responsible for deallocating the memory, but I'm not sure.
Is there a way to determine if that memory has been deallocated and force the core data to get it back if I need to access it? My managedObjectContext never gets deallocated, and the fetchedResultsController never does, either.
I thought maybe I needed to use the [managedObjectContext refreshObject:mergeData:] method, or the [managedObjectContext setRetainsRegisteredObjects:] method. Although, I'm under the impression that last one may not be the best bet since it will be more memory intensive (from what I understand).
These errors only popped up when I moved the core data calls into another class file, and they are random when they show up.
Any insight would be appreciated.
-Ryan
Sounds to me like you are not retaining objects you want to keep hanging around. If you are doing something like this:
NSArray *array = [moc executeFetchRequest:request error:&error];
you do not own the returned array and it will most likely disappear when the current autorelease pool is drained. This will occur when the run loop finishes processing the current event.
All this is speculation. If you want a proper answer, you need to post your code.
It's hard to know what the problem is based on your description, but you might want to look at the Core Data memory management guide. You shouldn't have to worry about memory management for managed objects and their entities (they're fetched and faulted automatically). When you talk about "properties," do you mean custom properties backed by ivars? If so, these should be released in didTurnIntoFault and allocd as needed (probably in the accessor).
I was struggling with a similar issue. I'm using a managed object class and want to set its properties dependent on user input. But the sometimes the properties and sometimes the whole managed object were deallocated.
After reading the Apple documentation http://developer.apple.com/library/IOs/#documentation/Cocoa/Conceptual/CoreData/Articles/cdMemory.html the chapter "The Role of the Managed Object Context" I learned that managed objects are released each run loop completes.
And there is the golden advice to set
[myMangedObjectContext setRetainsRegisteredObjects:YES];
(I had to set it in the init method (initWithNibName for me) of my view controller.)
You should also regard to retain only the objects you need to as explained in the documentation. But read it yourself.
If I'm not right please correct me.
I also made a class that handles all my CoreData fetching and stuff. I ran into a couple of gotcha's, so here are some tips. (If I am making any memory management errors in these examples, please let me know.)
Two things:
1) Made a "fetchFiredObject" method in the CoreData handler class. So when I want to get a managedObject that has all its variables and is a "fully feathered bird" so to speak, instead of doing:
aManagedObject *myManagedObject = [myCoreDataHandler.managedObjectStorageArray objectAtIndex:1];
int x = myManagedObject.someVariable.intValue;
instead I do:
aManagedObject *myManagedObject = [myCoreDataHandler fetchFiredObjectAtIndex:1];
int x = myManagedObject.someVariable.intValue;
And in myCoreDataHandler's fetchFiredObjectAtIndex:i method, we're going into the array, finding the object key at index i, then doing a fetchRequest for that object key, and returning the freshly-fetched managedObject so that it won't have been faulted or deallocated, etc. :D
2) When I create a new child viewController, I populate its "myCoreDataHandler" value from the parent upon creation. However, this happens on a subsequent line of code after the line of code that creates the new viewController. Therefore, any code in the child's viewDidLoad that tries to use myCoreDataHandler's methods will return empty objects because viewDidLoad completes before the parent's next line of code where it sets the values of globals in the child object. So make sure you are not accessing your "Core Data handling object" from within viewDidLoad or anything local methods called by viewDidLoad! Instead call them from the parent after creating the new viewController.