Change NSManagedObject property without triggering delegate methods? - iphone

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.

Related

copy NSManagedObject to a new object in memory

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.

Add existing objects to Core Data?

I couldn't find anything about this topic. I have NSManagedObjects that I don't use insertNewObject... I use alloc init, and then add them to array sort them alphabetically, and then I want to add them to entities and save the context. Any ideas on how to add them to entities, without making entirely new objects?
This may be more proper as a comment, but it is, in fact, the answer.
Do not do that. First, read the documentation, then use the API as directed.
Directly from the documentation for NSManagedObject:
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:).
Then, from the documentation for initWithEntity:insertIntoManagedObjectContext:
Important This method is the designated initializer for
NSManagedObject. You must not initialize a managed object simply by
sending it init.
Note, that the above statement is actually highlighted in an attention-getting box in the documentation.

Accessing an instance variable from a background thread

Say I have an instance variable MyObject that has been allocated and initialized. Then say I do this:
[backgroundThread performBlock:^{
//do something with MyObject that might take some time
}];
[self dismissModalViewController]; //this releases all instance variables, right?
So what happens is I have an NSManagedObjectContext called backgroundThread that does some work on an object in the background. This returns immediately and does the work in the background, and then dismissModalViewController is called, which deallocates all instance variables. So what if the modal view has now been dismissed, but the backgroundThread still needs to use the object? Is this an issue? What is the workaround?
And another thing: This MyObject is inserted into the managed object context backgroundThread. Does this mean that this NSManagedObjectContext will retain the object, even after dismissing the view?
I'm using ARC.
There are several things you need to think about here. First keep in mind that the block will capture whatever it refers to. So you might not need to do anything special and your code will work fine, depending on exactly what you are doing in your block. The rules for block capture are described in Apple's Block Programming Topics documentation and how each variable is treated depends on its type. In particular,
In a manually reference-counted environment, local variables used within the block are retained when the block is copied. Use of instance variables within the block will cause the object itself to be retained. If you wish to override this behavior for a particular object variable, you can mark it with the __block storage type modifier.
If you are using ARC, object variables are retained and released automatically as the block is copied and later released.
Another thing to consider is that access to the instance variables may or may not be thread safe. Accessing the instance variables through properties declared as atomic is a step in the right direction, but you may need to use mutex locks or other techniques to synchronize access depending on the specifics on the situation.
If you want to reference ivars or other properties of your (modal) view controller, you need to insure that the modal view controller still exists.
Here's a potentially useful hint from Apple's documentation on dismissModalViewControllerAnimated::
If you want to retain a reference to the receiver’s presented view
controller, get the value in the modalViewController property before
calling this method.
Another idea that might work would be to create & instantiate a separate object that encapsulates the data / objects you want to access from either the view controller, or any other thread.

myView.frame Vs. self.myView.frame

I know it's often advisable to use the #property accessors, and I know it's important to use self.myView = x instead of mView = x, but:
Isn't myView.frame sufficient? The AtomicElementFlippedView.m file in TheElements has self.wikipediaButton.frame=buttonFrame;. Shouldn't I leave out self if I'm getting/setting a property of my ivar and not the ivar itself?
It also does [self.wikipediaButton addTarget:...];. But shouldn't I leave out self here as well? Shouldn't I always call a function on the ivar, not the property? I.e., [wikipediaButton addTarget:...];
Thanks!
Matt
Both will work.
The main reason for using getters within a class is that code changes are easy. If you decide to store your data in a different fashion or to build it dynamically on request, there is a single point of change. With views it's not that important most of the time, but it can come handy when you replace that view with a complete view hierarchy (your original view being maybe part of it).
I'd say the main reason you'd want to use the property setter instead of direct ivar access is simply consistency. Yes, you can access the ivar directly, and you'll usually be just fine doing so. However, I'd say it's stylistically better to use the same method for both setting and getting. So if you're using property setters internally, you should also use property getters internally.

MVC, can model save/load its data?

Quick question, my data model is a singleton object and it contains a list of names that I want to archive. My idea is to make the model responsible for loading and saving it's own data. The model's load method will be called by the ViewController's viewDidLoad method and save by the ViewController's applicationWillTerminate. I could do the load/save directly within the ViewController, but this would be messy as the list of names are an instance variable of the model.
gary
You could just load and save in the init and dealloc methods (although it's common to call a save method explicitly). It's a good idea to encapsulate it within the model class. If you're loading from the network you might want to have a separate loadData method or something, rather than doing it from init.
Apple recommends using lazy initialization wherever possible, so I think you're heading down the right path, though you might want to consider making the method name something that looks like a property accessor, e.g. -names rather than -load (especially since there's a class method named +load that means something quite different).