EOKeyValueCoding
Volume Number: 16
Issue Number: 12
Column Tag: WebObjects
EOKeyValueCoding
By Sam Krishna and Patrick Taylor
Throughout this series we've asserted that programming in WebObjects is a richer,
more mature experience than any competing web application development
environment. A major reason for this superior programming experience can be laid at
the feet of EOKeyValueCoding.
EOKeyValueCoding is simultaneously a powerful protocol (in Objective C) and
interface (in Java). When the EOControl framework is imported, all Objective C
classes that inherit from NSObject receive EOKeyValueCoding behavior. (The
EOControl framework is imported automatically into WebObjects apps and
frameworks. You do not have to explicitly import it in to your WebObjects app or
framework project.) In Java, when the developer creates a subclass of
EOEnterpriseObject, EOCustomObject, EOGenericRecord or WOComponent, then
EOKeyValueCoding is available.
What is remarkable about EOKeyValueCoding is how universally powerful it is. With
this protocol/interface, the WebObjects and EOF frameworks know how to access
custom instance variables (ivars) from within your subclass. Using the methods
valueForKey() and takeValueForKey() (in Objective C valueForKey: and
takeValue:forKey:) WOF and EOF can access your ivars through standard API. In
addition, EOKeyValueCoding provides the bridge within EOF for effective
entity-relationship mapping.
In valueForKey(), this standard method allows a lookup of an ivar from both WOF and
EOF classes. Consider a WOComponent subclass that needs to fill in the value of a String
object in the dynamic WOString element. The WOString is bound to lastName of an
EnterpriseObject (EO) which represent the employees of a corporation.
Order of Access
1. The component subclass searches for a public accessor method based on
the key name. With a key of "lastName", valueForKey() looks for a method
named getLastName() or lastName(). In Objective C, it looks for a method
named getLastName or -lastName.
2. If a public accessor method isn't found, the component subclass searches
for a private accessor method based on key. Note that traditionally in the Apple
frameworks, a private method is distinguished by a preceding underbar. In
this case, valueForKey() looks for a method named _getLastName() or
_lastName(). In Objective C, it looks for a method named _getLastName or
-_lastName.
3. If an accessor method isn't found and the class method
accessInstanceVariablesDirectly returns true (in Java) or YES (in Objective
C), valueForKey() searches for an ivar based on the key name and returns its
value directly. For the key "lastName", this would be _lastName or lastName.
4. If neither an accessor method or an ivar is found, the default
implementation invokes handleQueryWithUnboundKey() in Java or
handleQueryWithUnboundKey: in Objective C. The default implementation of
this method will raise an NSException.
Sometimes exceptions are raised because although ivars have changed or been deleted
for some reason the component subclass or the frameworks still expect the ivar to
exist unchanged. In these situations after 10-15 minutes of proverbial pounding sand,
we would override handleQueryWithUnboundKey() and check to see if the disputed ivar
is being looked up, and if so, return nil or null.
EOKeyValueCoding API to Access Instance Variables
For another example, suppose that you have an EO using a BigDecimal or
NSDecimalNumber with "someDecimal" as one of its ivars.
Java
(BigDecimal)myEO.valueForKey("someDecimal");
note: you must always downcast your objects when using valueForKey()
in Java
Objective C
[myEO valueForKey:@"someDecimal"];
Here is the operational order for takeValueForKey() (takeValue:forKey:
in Objective C)
1. The EOKeyValueCoding methods search for a public accessor method of the
form setKey (setKey: in Objective C)
2. If a public accessor method isn't found, EOKeyValueCoding searches for a
private accessor method of the form _setKey (Objective C _setKey:) invoking