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.
Related
I am drawing a tableview via BehaviorRelay.
Currently, I am using the code below as a way to add data.
viewModel.user.append(Person(name: "king", phoneNumber: "12341234"))
viewModel.personObservable.accept(viewModel.user)
I wonder if this code changes the user itself so that the whole tableView is redrawn.
If so, what method can I use to change only the data I added?
The code presented causes the personObservable (which is actually a BehaviorRelay apparently,) to emit a next event that contains an entire array of Person values, not just the latest Person added. Importantly, it's not emitting the viewModel.user object (at least not conceptually) but an entirely different object that happens to be equal to viewModel.user.
The default dataSource, the one that you get when you call items with anything other than a DataSource object, will call reloadData on the table view. This doesn't cause "the whole tableView" to be redrawn though, but it will cause the table view to query the data source for all of the visible cells, even if they haven't changed.
If you only want the table view to load the new cell, then the data source object needs to be smart enough to compare the new array with the array it's currently displaying so it can figure out which values are different and add/remove/move cells as appropriate, instead of just calling reloadData. As #Sweeper said in the comments, the RxDataSources library contains a set of data source classes that have that logic built in. If you wanted to reinvent the wheel, just write a class that conforms to both RxTableViewDataSourceType & UITableViewDataSource and implement the diffing yourself.
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]];
}
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.
Is there any way (or tricks) where I can modify an NSManagedObject currently held by a delegated NSFetchedResultsController without triggering the didChangeObject: and controllerWillChangeContent: delegate methods?
For example, current if I change myObject.property = #"hello";, the delegate methods are triggered and updates are made to my table view, but I don't want that to happen, but only for certain changes where I explicitly specify, not all changes.
The setPrimitiveValue:forKey: method from NSManagedObject does exactly this, e.g.
[myObject setPrimitiveValue:#"hello" forKey:#"property"]
or, using the dynamically generated accessor methods:
[myObject setPrimitiveProperty:#"hello"]
But you should read the documentation of that method, because there are some "Special Considerations".
A different approach could be to create a "nested managed object context" and do all the modifications on that child context. Only when the child context is saved, the changes are propagated to the parent context.
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.