Is there a way to change default values of a core data attribute - objective-c

I would like to change the default value of some of the attributes in my core data model dynamically.
For instance, my app deals with real estate investment, and I have an attribute pertaining to interest rate (the type Float). If the user enters an interest rate of 3.5% (float value would be 3.5) for a particular property they are analyzing, I would like the value for the next property they analyze to automatically populate with 3.5.
Is there a way to accomplish this without subclassing NSManagedObject?

Good question - by default, managed objects are initialized with the default values given in the managed object model. But like you say, sometimes you might want a dynamic default value (the example Apple use in their own documentation is using the current date/time as a default value).
Unfortunately I don't believe there's a way to do this without subclassing NSManagedObject. There's an Apple recommended way to do this - rather than overriding the init method (not recommended), you instead use the awakeFromInsert method, which is called when the object in question is first inserted into the managed object context.
Here's what Apple say from their own docs:
awakeFromInsert:
You typically use this method to initialize special default property values. This method is invoked only once in the object's lifetime.
If you want to set attribute values in an implementation of this method, you should typically use primitive accessor methods (either setPrimitiveValue:forKey: or—better—the appropriate custom primitive accessors). This ensures that the new values are treated as baseline values rather than being recorded as undoable changes for the properties in question.
So to answer your original question - I can't think of a way to do this without subclassing NSManagedObject, and subclassing is the officially recommended approach for handling dynamic default values.

Related

Is it ok to Serialize Value based objects if the application never relies on its object identity?

Sonar shows
Make this value-based field transient so it is not included in the
serialization of this class.
This is a future-proof bug when value-based class will be released.
So, if the application never relies on its object identity can I make value-based objects non-transient?
To make a field of a value-based class non-transient, the value based class must be serializable. So it’s actually a design decision not made by you.
If the designer declares a class to be value-based and implementing Serializable, they assume that value based classes and Serialization are compatible and will stay so.
We don’t know, how the final value type implementation will look like, but the migration path offered by the JRE developers, e.g. when introducing the immutable lists, being value based and serializable, should be taken, rather than assuming that there are additional rules and constraints beyond the specification.
After all, there is no reason to assume that Serialization won’t work with value types. It supports primitive values as well and has been adapted in the past too, e.g. when enum support was added. It’s not clear whether it will always store the values then or still support back references like with ordinary objects or perform an entirely different canonicalization, but as long as you don’t rely on the object identity, as was your premise, you’re on the safe side, as either strategy would work with your code.

Cocoa Binding, does it matter if the view or the controller is the receiver?

Using Apple's Examples, is there a difference between:
[joystick bind:#"angle" toObject:GraphicController withKeyPath:#"selection.shadowAngle" options:options];
and
[GraphicController bind:#"selection.shadowAngle" toObject:joystick withKeyPath:#"angle" options:options];
So according to the documentation, binding sets it up so using KVO, the receiver observes the object, and uses KVC to set properties on the object. Here are the relevant figures they provide.
But in my mind, I don't see why this couldn't be flipped? Why can't the controller observe changes to the values on the view w/ KVO, and why can't it set values on the view w/ KVC?
Yes, it matters.
First, not all binding names are property names. For example, NSTextField has a "value" binding (you could use the NSValueBinding constant), but it has no value property.
Second, not all properties are KVO-compliant. In general, the assumption must be that a property is not KVO-compliant unless it is documented to be. Many properties of views are not KVO-compliant. A binding that has the same name can still work, because the class implements the binding and knows when its own internal state changes without relying on KVO.
Third, it is usually the case that there needs to be a specific implementation of -bind:toObject:withKeyPath:options: on the receiver to implement the binding. NSObject provides a default implementation of the NSKeyValueBindingCreation informal protocol, but it is fairly limited. For example, it is read-only. It observes the observableController for changes in the property at the key path and forwards new values to the property on the receiver named by the binding name, but it does not do the reverse. Changes to the receiver's properties will not be forwarded to the observableController at the key path.
That's usually not what you wanted from a binding, especially if you reverse the roles. So, you need a custom implementation. The documentation that you linked to shows how such a custom implementation of -bind:... could be written.
Finally, there are services that controllers perform when they are bound to that they can't perform when they are thing whose binding is being set. This mostly centers around the NSEditor and NSEditorRegistration protocols and the implementation of them on NSController (which is inherited by its subclasses).
For example, when a text field is bound to a controller, it registers itself with that controller when it starts editing. Later, some other code needs to be sure editing is complete and all bindings have been updated to reflect that editing. It calls one of the -commitEditing... methods on the controller. This will, in turn, call -commitEditing... on the text field.
This doesn't work if the roles are reversed.

Simple setter function or set with a property?

Just curious to know what difference does it make if one uses a setter function or a property to set a value? Which of the above two should be preferred?
column.setWidth(10);
column.width = 10;
Well, that largely depends on what programming language you are using, or, in other words, whether it supports the concept of properties or not. However, lets look at the problem from a general perspective.
The very basic point of view is properties are just plain syntactic sugar, making reading and writing values to some assumed backing field easier and, which is the important point, defining a clear contract for your code's user. Assumed because there needs not be any backing field at all or they can be many.
The high-level semantic difference between a setter function and a native property setter can be thought as follows:
A setter function is primarily still a function, hence the reader assumes it executes certain action using its arguments; being actually a setter is then just a convention.
A native property setter is primarily a way to write a value into some assumed backing storage / into the backing object; there's no implied notion of executing an action even though the hidden implementation details of the setter may work like that.
Many practicle ramifications of using property accessors (getters and setter) were discussed in this question and its answers.
Prefer properties. Actually it depends on your language. If you develop Python that all attributes are public in Python.

Change default values for certain attributes for future NSManagedObject insertions?

How could I go about doing this programmatically? Subclass NSManagedObject and override -(void)awakeFromInsert;? Then I suppose set the attribute values in the methods implementation?
The way to get Core Data to do this, and IMO the right way to handle the situation, is to add another version of the model with the default values set on those properties, and configure automatic model migration.
I don't know whether migration will apply the new defaults to existing entities with nil values. (My guess would be not. Testing would bear the answer.)
Is there some reason you need to leave alone existing entities with nil values?
-awakeFromInsert would indeed be the right place to do this kind of thing in code.

flexjson and versioning : how accommodating change is flexjson?

I'm considering using flexjson to serialise my business objects to a file in an android application, simply using JSONSerializer().deepSerialise(myObject) and JSONDeserializer().deserialise(jsonString) with all the default transformers and object factories.
I'm hoping that once the application is released any changes to the business model should be accommodated by writing flexjsons transformers and object factories in the new release to maintain compatibility with previous versions.
What I'm not sure about is what changes the default transformers and object factories can cope with.
i.e if I add a field to a class and deserialise from an old version without the field into the new class will it fail or will the new field be null or 0 (if a number). Same question if I remove a field, what happens.
In standard java serialisation this is all documented here..
http://docs.oracle.com/javase/7/docs/platform/serialization/spec/version.html
But I cant find the equivalent information for flexjson, that deals explicitly with the issues surrounding versioning of objects, Is there any?
Cheers,
Phil.
Flexjson will look at the JSON first to find any fields it contains, and then looks for those fields on the Object you are deserializing into. So adding new fields to an object will not cause the deserialization process to fail. The new field will just not be populated from the JSON object (ie it will retain the value(s) set in the constructor or the initialization values).
If you remove a field from an object in the future Flexjson will simply not deserialize that value into the object because it won't find a setter for it.
So you can think about the getter/setter functions as a declaration on the JSON of what you want out of it. You aren't required to serialize/deserialize all values from the JSON object.
The only part that gets really tricky is if you rename fields, or change types on a field. Renaming field can be handled by keeping the older setter around and internally setting the new field in that older setter. You can mark it private or protected to hide it from the outside and Flexjson will still use it. If you change the type it is much more tricky. One option is to keep the older setter with the prior type around (like setFoo(String) and setFoo(List)) and adapt to the new type. The other option is to write your ObjectFactory to translate between to the two potential types. This of course is the hardest to do. The last option is don't do this without changing the name of the field, and use one of the other methods to translate.