Copyright: Copyright © NeXT Software Inc. 1996


Control Types And Constants

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Defined Types

EODeleteRule

DECLARED IN	EOControl/EOClassDescription.h

SYNOPSIS	typedef enum {

EODeleteRuleNullify = 0,

EODeleteRuleCascade,

EODeleteRuleDeny

} EODeleteRule;

DESCRIPTION	Used by EOClassDescription to specify the delete rule for a relationship. See the EOClassDescription class specification for more information.

EOObserverPriority

DECLARED IN	EOControl/EOObserver.h

SYNOPSIS	typedef enum {

EOObserverPriorityImmediate,

EOObserverPriorityFirst,

EOObserverPrioritySecond,

EOObserverPriorityThird,

EOObserverPriorityFourth,

EOObserverPriorityFifth,

EOObserverPrioritySixth,

EOObserverPriorityLater

} EOObserverPriority;

DESCRIPTION	Used by EODelayedObservers and EODelayedObserverQueues to specify a priority for receiving notifications. See the specifications for these classes for more information.

Symbolic Constants

Run Loop Orderings

DECLARED IN	EOControl/EOEditingContext.h

SYNOPSIS	EOEditingContextFlushChangesRunLoopOrdering	300000

DESCRIPTION	Used by EOEditingContext as the order argument to NSRunLoop’s performSelector:target:argument:order:modes: method.

DECLARED IN	EOControl/EOUndoManager.h

SYNOPSIS	EOUndoManagerCloseGroupingRunLoopOrdering	350000

DESCRIPTION	Used by EOUndoManager as the order argument to NSRunLoop’s performSelector:target:argument:order:modes: method.

DECLARED IN	EOControl/EOObserver.h

SYNOPSIS	EOFlushDelayedObserversRunLoopOrdering	400000

DESCRIPTION	Used by EODelayedObserverQueue as the order argument to NSRunLoop’s performSelector:target:argument:order:modes: method.

Observer Priorities

DECLARED IN	EOControl/EOObserver.h

SYNOPSIS	EOObserverNumberOfPriorities	((unsigned)EOObserverPriorityLater + 1)

Comparison Selectors

DECLARED IN	EOControl/EOQualifier.h

SYNOPSIS	EOQualifierOperatorEqual	@selector(isEqualTo:)

EOQualifierOperatorNotEqual	@selector(isNotEqualTo:)

EOQualifierOperatorLessThan	@selector(isLessThan:)

EOQualifierOperatorGreaterThan	@selector(isGreaterThan:)

EOQualifierOperatorLessThanOrEqualTo	@selector(isLessThanOrEqualTo:)

EOQualifierOperatorGreaterThanOrEqualTo	@selector(isGreaterThanOrEqualTo:)

EOQualifierOperatorContains	@selector(doesContain:)

EOQualifierOperatorLike	@selector(isLike:)

DESCRIPTION	Used to specify a selector to use to compare objects in an EOQualifier. See the EOQualifier class specification for more information.

Sort Ordering Selectors

DECLARED IN	EOControl/EOSortOrdering.h

SYNOPSIS	EOCompareAscending	@selector(compareAscending:)

EOCompareDescending	@selector(compareDescending:)

EOCompareCaseInsensitiveAscending	@selector(compareCaseInsensitiveAscending:)

EOCompareCaseInsensitiveDescending	@selector(compareCaseInsensitiveDescending:)

DESCRIPTION	Used to specify a selector to use to order objects in an EOSortOrdering. See the EOSortOrdering class specification for more information.

Global Variables

Aggregate Exception Key

DECLARED IN	EOControl/EOClassDescription.h

SYNOPSIS	EOCONTROL_EXTERN NSString *EOAdditionalExceptionsKey;

Exception Names

DECLARED IN	EOControl/EOClassDescription.h

SYNOPSIS	EOCONTROL_EXTERN NSString *EOValidationException;

Notification Names

DECLARED IN	EOControl/EOClassDescription.h

SYNOPSIS	EOCONTROL_EXTERN NSString *EOClassDescriptionNeededNotification;

DECLARED IN	EOControl/EOObjectStoreCoordinator.h

SYNOPSIS	EOCONTROL_EXTERN NSString *EOCooperatingObjectStoreWasAdded;

EOCONTROL_EXTERN NSString *EOCooperatingObjectStoreWasRemoved;

DECLARED IN	EOControl/EOGlobalID.h

SYNOPSIS	EOCONTROL_EXTERN NSString *EOGlobalIDChangedNotification;

DECLARED IN	EOControl/EOUndoManager.h

SYNOPSIS	EOCONTROL_EXTERN NSString *EOUndoManagerCheckpointNotification;

DECLARED IN	EOControl/EOObjectStore.h

SYNOPSIS	EOCONTROL_EXTERN NSString *EOObjectsChangedInStoreNotification;

EOCONTROL_EXTERN NSString *EOInvalidatedAllObjectsInStoreNotification;

DECLARED IN	EOControl/EOEditingContext.h

SYNOPSIS	EOCONTROL_EXTERN NSString *EOObjectsChangedInEditingContextNotification;

EOCONTROL_EXTERN NSString *EOEditingContextDidSaveChangesNotification;


EOAndQualifier

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	EOQualifier : NSObject

Conforms To:	EOQualifierEvaluation

EOQualifierSQLGeneration

Declared In:	EOControl/EOQualifier.h

Class Description

EOAndQualifier is a subclass of EOQualifier that contains multiple qualifiers. EOAndQualifier adopts the EOQualifierEvaluation protocol, which defines the method evaluateWithObject: for in-memory evaluation. When an EOAndQualifier object receives an evaluateWithObject: message, it evaluates each of its qualifiers until one of them returns NO. If one of its qualifiers returns NO, the EOAndQualifier object returns NO immediately. If all of its qualifiers return YES, the EOAndQualifier object returns YES.

Adopted Protocols

EOQualifierEvaluation 	− evaluateWithObject:

EOQualifierSQLGeneration	− sqlStringForSQLExpression:

− schemaBasedQualifierWithRootEntity:

Method Types

Initializing an EOAndQualifier	− initWithQualifierArray:

− initWithQualifiers:

Returning an EOAndQualifier’s qualifiers

− qualifiers

Instance Methods

evaluateWithObject:

@protocol EOQualifierEvaluation

− (BOOL)evaluateWithObject:(id)anObject

Returns YES if anObject satisfies the qualifier, NO otherwise. When an EOAndQualifier object receives an evaluateWithObject: message, it evaluates each of its qualifiers until one of them returns NO. If any of its qualifiers returns NO, the EOAndQualifier object returns NO immediately. If all of its qualifiers return YES, the object returns YES. This method can raise one of several possible exceptions if an error occurs. If your application allows users to construct arbitrary qualifiers (such as through a user interface), you may want to put exception handlers around this method to properly respond to errors (for example, by displaying a panel saying that the user typed a poorly formed qualifier).

initWithQualifierArray:

− initWithQualifierArray:(NSArray *)qualifiers

Initializes the receiver with the qualifiers qualifiers and returns self. This method is the designated initializer for EOAndQualifier.

initWithQualifiers:

− initWithQualifiers:(EOQualifier *)qualifiers, ...

Initializes the receiver with the nil-terminated list of qualifiers qualifiers. Works by invoking initWithQualifierArray:. For example, the following code excerpt constructs three qualifiers, qual1, qual2, and qual3. It then uses these qualifiers to initialize an EOAndQualifier, andQual. andQual is then used to filter an in-memory array.

NSArray *guests;    /* Assume this exists. */

EOQualifier *qual1, *qual2, *qual3, *andQual;

qual1 = [EOQualifier qualifierWithQualifierFormat:@"lastName = 'Nunez'"];

qual2 = [EOQualifier qualifierWithQualifierFormat:@"lastName = 'Wren'"];

qual3 = [EOQualifier qualifierWithQualifierFormat:@"lastName = 'Wilson'"];

andQual = [[EOAndQualifier alloc] initWithQualifiers:qual1, qual2, qual3, nil];

return [guests filteredArrayUsingQualifier:orQual];

qualifiers

− (NSArray *)qualifiers

 Returns the receiver’s qualifiers.


EOClassDescription

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	NSObject

Declared In:	EOControl/EOClassDescription.h

Class Description

The EOClassDescription class provides a mechanism for extending classes by giving them access to metadata not available in the Objective-C run-time system. This is achieved as follows:

•	EOClassDescription provides a bridge between enterprise objects and the metadata contained in an external source of information, such as an EOModel. It defines a standard interface for accessing the information in an external source. It also manages the registration of EOClassDescription objects in your application.

•	Enterprise Objects Framework extends NSObject by adding several EOClassDescription-related methods to it. An enterprise object class can either provide its own implementation of these methods or it can accept the default implementations. These methods enable an enterprise object to take advantage of behaviors defined by the Framework, such as undo and validation. This is discussed in more detail in the section “Using EOClassDescription.”

Enterprise Objects Framework implements a default subclass of EOClassDescription, EOEntityClassDescription. EOEntityClassDescription extends the behavior of enterprise objects by deriving information about them (such as NULL constraints and referential integrity rules) from an associated model file.

How Does It Work?

As noted above, Enterprise Objects Framework implements a default subclass of EOClassDescription, EOEntityClassDescription. In the typical scenario in which an enterprise object has a corresponding model file, a particular operation (such as validating a value) results in the broadcast of an EOClassDescriptionNeeded notification. When an EOModel object receives this notification it registers the metadata (class description) for the EOEntity on which the enterprise object is based.

An enterprise object takes advantage of the metadata registered for it by using the EOClassDescription-related methods that the Framework adds to NSObject. Primary among these methods is classDescription, which returns the class description associated with the enterprise object. Through this class description the enterprise object has access to all of the information relating to its entity in an EOModel file.

In addition to methods that return information based on an enterprise object’s class description, the EOClassDescription-related methods that the Framework adds to NSObject include methods that are automatically invoked when a particular operation occurs. These include validation methods and methods that are invoked whenever an enterprise object is inserted or fetched.

All of this comes together in your running application. When a user tries to perform a particular operation on an enterprise object (such as attempting to delete it), the EOEditingContext sends these validation messages to your enterprise object, which in turn (by default) forwards them to its EOClassDescription. Based on the result, the operation is either accepted or refused. For example, referential integrity constraints in your model might state that you can’t delete an department object that has employees. If a user attempts to delete a department that has employees, an exception is returned and the deletion is refused.

Using EOClassDescription

For the most part, you don’t need to programmatically interact with EOClassDescription. It extends the behavior of your enterprise objects transparently. However, there are two cases in which you do need to programmatically interact with it:

•	When you override EOClassDescription-related NSObject methods in an enterprise object class

These methods are used to perform validation and to intervene when enterprise objects based on EOModels are created and fetched. For objects that don’t have EOModels, you can override a different set of NSObject methods; this is described in more detail in the section “Working with Objects That Don’t Have EOModels."

•	When you create a subclass of EOClassDescription

Overriding Methods in an Enterprise Object

As described above, Enterprise Objects Framework adds several EOClassDescription-related methods to NSObject. It’s common for enterprise object classes to override the following methods to either perform validation, to assign default values (awakeFromInsertionInEditingContext:), or to provide additional initialization to newly fetched objects (awakeFromFetchInEditingContext:):

validateValue:forKey:

validateForSave

validateForDelete

validateForInsert

validateForUpdate

awakeFromInsertionInEditingContext:

awakeFromFetchInEditingContext:

For example, an enterprise object class can implement a validateForSave method that checks the value of a salary property before allowing the value to be saved to the database:

- (NSException *)validateForSave

{

if (salary > 1500)

return [NSException validationExceptionWithFormat:

@"That salary is too high!"];

// pass the check on to the EOClassDescription

return [super validateForSave];

}

For more discussion of this subject, see the chapter “Designing Enterprise Objects” in the Enterprise Objects Framework Developer’s Guide, and the class specification “Extensions to NSObject.”

Working with Objects That Don’t Have EOModels

Although an EOModel is the most common source of an EOClassDescription for a class, it isn’t the only one. Objects that don’t have an EOModel can implement EOClassDescription methods directly as instance methods, and the rest of the Framework will treat them just as it does enterprise objects that have this information provided by an external EOModel.

There are a few reasons you might want to do this. First of all, if your object implements the methods entityName, attributeKeys, toOneRelationshipKeys, and toManyRelationshipKeys, EOEditingContexts can snapshot the object and thereby provide undo for it.

For example, the following code excerpt shows an implementation of attributeKeys for a Circle class:

- (NSArray *)attributeKeys {

    static NSArray *array = nil;

    if (!array)

        array = [[NSArray alloc] initWithObjects:@"radius", @"x",

 	@"y", @"color", nil];

    return array;

}

Secondly, you might want to implement EOClassDescription’s validation or referential integrity methods to add these features to your classes.

Implementing EOClassDescription methods on a per-class basis in this way is a good alternative to creating a subclass of EOClassDescription.

Creating a Subclass of EOClassDescription

You create a subclass of EOClassDescription when you want to use an external source of information other than an EOModel to extend your objects. Another possible scenario is if you’ve added information to an EOModel (such as in its user dictionary) and you want that information to become part of your class description—in that case, you’d probably want to create a subclass of EOEntityClassDescription.

When you create a subclass of EOClassDescription, you only need to implement the methods that have significance for your subclass.

If you’re using an external source of information other than an EOModel, you need to decide how to register class descriptions, which you do by invoking the method registerClassDescription:forClass:. You can either invoke registerClassDescription:forClass: in response to an EOClassDescriptionNeeded notification, or you can invoke it at the time you initialize your application (in other words, you can register all potential class descriptions ahead of time). The default implementation in Enterprise Objects Framework is based on responding to an EOClassDescriptionNeeded notification. When EOModel objects receive this notification, they supply a class description for the specified class by invoking registerClassDescription:forClass:.

EOEntityClassDescription

There are only three methods in EOClassDescription have meaningful implementations (that is, that don’t either return nil or simply return): invalidateClassDescriptionCache, registerClassDescription:forClass:, and propagateDeleteForObject:editingContext:. The default behavior of the rest of the methods in Enterprise Objects Framework comes from the implementation in the EOClassDescription subclass EOEntityClassDescription. For more information, see the EOEntityClassDescription class specification.

Method Types

Managing EOClassDescriptions	+ invalidateClassDescriptionCache

+ registerClassDescription:forClass:

Allocating new object instances	− createInstanceWithEditingContext:globalID:zone:

Propagating delete	− propagateDeleteForObject:editingContext:

Returning information from the EOClassDescription

− entityName

− attributeKeys

− classDescriptionForDestinationKey:

− toManyRelationshipKeys

− toOneRelationshipKeys

− inverseForRelationshipKey:

− ownsDestinationObjectsForRelationshipKey:

− deleteRuleForRelationshipKey:

Performing validation	− validateObjectForDelete:

− validateObjectForSave:

− validateValue:forKey:

Handling newly inserted and newly fetched objects

− awakeObject:fromFetchInEditingContext:

− awakeObject:fromInsertionInEditingContext:

Class Methods

invalidateClassDescriptionCache

+ (void)invalidateClassDescriptionCache

Flushes the class description cache. Because the EOModel objects in an application supply and register EOClassDescriptions on demand, the cache continues to be repopulated as needed after you invalidate it.

You’d use this method when a provider of EOClassDescriptions (such as an EOModel) has newly become available, or is about to go away. However, you should rarely need to directly invoke this method unless you’re using an external source of information other than an EOModel.

registerClassDescription:forClass:

+ (void)registerClassDescription:(EOClassDescription *)description forClass:(Class)class

Registers an EOClassDescription object for class in the EOClassDescription cache. You should rarely need to directly invoke this method unless you’re using an external source of information other than an EOModel.

Instance Methods

attributeKeys

− (NSArray *)attributeKeys

Overridden by subclasses to return an array of keys for attributes of the object. Attributes contain data (such as NSNumbers and NSStrings), as opposed to pointers to other enterprise objects. EOClassDescription’s implementation of this method returns nil.

See also:	− entityName, − toOneRelationshipKeys, − toManyRelationshipKeys

awakeObject:fromFetchInEditingContext:

− (void)awakeObject:(id)object

fromFetchInEditingContext:(EOEditingContext *)anEditingContext

Overridden by subclasses to perform standard post-fetch initialization for object in anEditingContext. EOClassDescription’s implementation of this method does nothing.

awakeObject:fromInsertionInEditingContext:

− (void)awakeObject:(id)object

fromInsertionInEditingContext:(EOEditingContext *)anEditingContext

Overridden by subclasses to propagate inserts for the newly inserted object in anEditingContext. More specifically, if object has a relationship (or relationships) that propagates the object’s primary key and if no object yet exists at the destination of that relationship, subclasses should create the new object at the destination of the relationship. EOClassDescription’s implementation of this method does nothing.

classDescriptionForDestinationKey:

− (EOClassDescription *)classDescriptionForDestinationKey:(NSString *)detailKey

Overridden by subclasses to return the class description for objects at the destination of the relationship identified by detailKey. For example, the statement:

[project classDescriptionForDestinationKey:@"leader"]

might return the class description for the Employee class. EOClassDescription’s implementation of this method returns nil.

createInstanceWithEditingContext:globalID:zone:

− (id)createInstanceWithEditingContext:(EOEditingContext *)anEditingContext globalID:(EOGlobalID *)globalID zone:(NSZone *)zone

Overridden by subclasses to allocate an object of the appropriate class in anEditingContext, with globalID, in zone. If the object responds to initWithEditingContext:classDescription:globalID subclasses should invoke that method, otherwise they should invoke init. Implementations of this method should return an autoreleased object. Enterprise Objects Framework uses this method to allocate new instances of objects when fetching existing enterprise objects or inserting new ones in an EODisplayGroup. EOClassDescription’s implementation of this method returns nil.

deleteRuleForRelationshipKey:

− (EODeleteRule)deleteRuleForRelationshipKey:(NSString *)relationshipKey

Overridden by subclasses to return a delete rule indicating how to treat the destination of the given relationship when the receiving object is deleted. For example, the class description for an Invoice object might return EODeleteRuleCascade for the relationship lineItems, because when an Invoice is removed from an external store, its line items should be removed also. EOClassDescription’s implementation of this method returns the delete rule EODeleteRuleNullify. In the common case, the delete rule for an enterprise object is defined in its EOModel.

entityName

− (NSString *)entityName

Overridden by subclasses to return a unique type name for objects of this class. EOEntityClassDescription returns its EOEntity’s name. EOClassDescription’s implementation of this method returns nil.

See also:	− attributeKeys, − toOneRelationshipKeys, − toManyRelationshipKeys

inverseForRelationshipKey:

− (NSString *)inverseForRelationshipKey:(NSString *)relationshipKey

Overridden by subclasses to return the name of the relationship pointing back at the receiver from the destination of the relationship specified by relationshipKey. For example, suppose an Employee object has a relationship called department to a Department object, and Department has a relationship called employees back to Employee. The statement:

[employee inverseForRelationshipKey:@"department"]

returns the string “employees”.

EOClassDescription's implementation of this method returns nil.

ownsDestinationObjectsForRelationshipKey:

− (BOOL)ownsDestinationObjectsForRelationshipKey:(NSString *)relationshipKey

Overridden by subclasses to return YES or NO to indicate whether the objects at the destination of the relationship specified by relationshipKey should be deleted if they are removed from the relationship (and not transferred to the corresponding relationship of another object). For example, an Invoice object owns its line items. If a LineItem object is removed from an Invoice it should be deleted since it can’t exist outside of an Invoice. EOClassDescription's implementation of this method returns NO. In the common case, this behavior for an enterprise object is defined in its EOModel.

propagateDeleteForObject:editingContext:

− (void)propagateDeleteForObject:(id)object

editingContext:(EOEditingContext *)anEditingContext

Propagates a delete operation for object in anEditingContext, according to the delete rules specified in the object’s EOModel. This method is invoked whenever a delete operation needs to be propagated, as indicated by the delete rule specified for the EOEntity’s relationship key.

See also:	− deleteRuleForRelationshipKey:

toManyRelationshipKeys

− (NSArray *)toManyRelationshipKeys

Overridden by subclasses to return the keys for the to-many relationship properties of the receiver. To-many relationship properties contain arrays of pointers to other enterprise objects. EOClassDescription's implementation of this method returns nil.

See also:	− entityName, − toOneRelationshipKeys, − attributeKeys

toOneRelationshipKeys

− (NSArray *)toOneRelationshipKeys

Overridden by subclasses to return the keys for the to-one relationship properties of the receiver. To-one relationship properties are pointers to other enterprise objects. EOClassDescription's implementation of this method returns nil.

See also:	− entityName, − toManyRelationshipKeys, − attributeKeys

validateObjectForDelete:

− (NSException *)validateObjectForDelete:(id)object

Overridden by subclasses to determine whether it’s permissible to delete the object. Subclasses should return nil if the delete operation should proceed, or an unevaluated exception containing a user-presentable (localized) error message if not. EOClassDescription's implementation of this method returns nil.

validateObjectForSave:

− (NSException *)validateObjectForSave:(id)object

Overridden by subclasses to determine whether the values being saved for the object are acceptable. Subclasses should return nil if the values are acceptable and the save operation should therefore proceed, or an unevaluated exception containing a user-presentable (localized) error message if not. EOClassDescription's implementation of this method returns nil.

validateValue:forKey:

− (NSException *)validateValue:(id *)valueP forKey:(NSString *)key

Overridden by subclasses to validate the value pointed to by valueP. Subclasses should return nil if the value is acceptable, or an unevaluated exception containing a user-presentable (localized) error message if not. Implementations can replace *valueP with a converted value (for example, an EOAttribute might convert an NSString to an NSNumber). EOClassDescription's implementation of this method returns nil.

Notifications

The following notification is declared by EOClassDescription and posted by enterprise objects in your application.

EOClassDescriptionNeeded

Notification Object	Enterprise object class

userInfo Dictionary	None

One of the EOClassDescription-related methods that Enterprise Objects Framework adds to NSObject to extend the behavior of enterprise objects is classDescription. The first time an enterprise object receives a classDescription message (for example, when changes to the object are being saved to the database), it posts EOClassDescriptionNeeded to notify observers (by default, the associated EOModel object) that a class description is needed. The observer then locates the appropriate class description and registers it in the application.


EOControl
Contents

Classes

EOAndQualifier

EOClassDescription

EOCooperatingObjectStore

EODataSource

EODelayedObserver

EODelayedObserverQueue

EODetailDataSource

EOEditingContext

EOFault

EOFaultHandler

EOFetchSpecification

EOGlobalID

EOKeyComparisonQualifier

EOKeyValueQualifier

EONotQualifier

EONull

EOObjectStore

EOObjectStoreCoordinator

EOObserverCenter

EOObserverProxy

EOOrQualifier

EOQualifier

EOSortOrdering

EOTemporaryGlobalID

EOUndoManager

NSArrayAdditions

NSExceptionAdditions

NSObjectAdditions

ValueClassAdditions

Protocols

EOEditors

EOMessageHandlers

EOObserving

EOQualifierEvaluation

Types and Constants

ControlTypesAndConstants


EOCooperatingObjectStore

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	EOObjectStore : NSObject

Conforms To:	NSObject (NSObject)

Declared In:	EOControl/EOObjectStoreCoordinator.h

Class Description

EOCooperatingObjectStore is an abstract class that defines the basic interface for object stores that work together to manage data from several distinct data repositories. The interaction between EOCooperatingObjectStores is managed by another class, EOObjectStoreCoordinator. The EOObjectStoreCoordinator communicates changes to its EOCooperatingObjectStores by handing them an EOEditingContext. Each EOCooperatingObjectStore examines the modified objects in the EOEditingContext and determines if it’s responsible for handling the changes. When an EOCooperatingObjectStore has changes that need to be handled by another store, it communicates the changes to the other store back through the EOObjectStoreCoordinator.

For relational databases, Enterprise Objects Framework provides a concrete subclass of EOCooperatingObjectStore, EODatabaseContext. The EODatabaseContext class represents a single connection to a database server. EODatabaseContext fetches and saves objects on behalf of one or more EOEditingContexts. However, EODatabaseContext and EOEditingContext don’t interact with each other directly—an EOObjectStoreCoordinator acts as a mediator between them.

Method Types

Committing or discarding changes	− commitChanges

− performChanges

− rollbackChanges

− prepareForSaveWithCoordinator:editingContext:

− recordChangesInEditingContext

− recordUpdateForObject:changes:

Returning information about objects	− valuesForKeys:object:

Determining if the EOCooperatingObjectStore is responsible for a particular operation

− ownsObject:

− ownsGlobalID:

− handlesFetchSpecification:

Instance Methods

commitChanges

− (void)commitChanges

Overridden by subclasses to commit the transaction. Raises an exception if an error occurs; the error message indicates the nature of the problem.

See also:	− performChanges, − commitChanges,

− saveChangesInEditingContext: (EOObjectStoreCoordinator)

handlesFetchSpecification:

− (BOOL)handlesFetchSpecification:(EOFetchSpecification *)fetchSpecification

Overridden by subclasses to return YES if the receiver is responsible for fetching the objects described by fetchSpecification. For example, EODatabaseContext determines whether it’s responsible based on fetchSpecification’s entity name.

See also:	 − ownsGlobalID:, − ownsObject:

ownsGlobalID:

− (BOOL)ownsGlobalID:(EOGlobalID *)globalID

Overridden by subclasses to return YES if the receiver is responsible for fetching and saving the object identified by globalID. For example, EODatabaseContext determines whether it’s responsible based on the entity associated with globalID.

See also:	 − handlesFetchSpecification:, − ownsObject:

ownsObject:

− (BOOL)ownsObject:(id)object

Overridden by subclasses to return YES if the receiver is responsible for fetching and saving object. For example, EODatabaseContext determines whether it’s responsible based on the entity associated with object.

See also:	 − ownsGlobalID:, − handlesFetchSpecification:

performChanges

− (void)performChanges

Overridden by subclasses to transmit changes to the receiver’s underlying database. Raises an exception if an error occurs; the error message indicates the nature of the problem.

See also:	− commitChanges, − rollbackChanges,

− saveChangesInEditingContext: (EOObjectStoreCoordinator)

prepareForSaveWithCoordinator:editingContext:

− (void)prepareForSaveWithCoordinator:(EOObjectStoreCoordinator *)coordinator editingContext:(EOEditingContext *)context

Overridden by subclasses to notify the receiver that a multi-store save operation is beginning. For example, the receiver might prepare primary keys for newly inserted objects so that they can be handed out to other EOCooperatingObjectStores upon request. The receiver should be prepared to receive the messages recordChangesInEditingContext: and recordUpdateForObject:changes:.

After performing these methods, the receiver should be prepared to receive the possible messages performChanges and then commitChanges or rollbackChanges.

recordChangesInEditingContext

− (void)recordChangesInEditingContext

Overridden by subclasses to instruct the receiver to examine the changed objects in the receiver’s EOEditingContext, record any operations that need to be performed, and notify the receiver’s EOObjectStoreCoordinator of any changes that need to be forwarded to other EOCooperatingObjectStores.

See also:	 − prepareForSaveWithCoordinator:editingContext:, − recordUpdateForObject:changes:

recordUpdateForObject:changes:

− (void)recordUpdateForObject:(id)object changes:(NSDictionary *)changes

Overridden by subclasses to communicate from one EOCooperatingObjectStore to another (through the EOObjectStoreCoordinator) that changes need to be made to an object. For example, an insert of an object in a relationship property might require changing a foreign key property in an object owned by another EOCooperatingObjectStore. This method is primarily used to manipulate relationships.

See also:	 − prepareForSaveWithCoordinator:editingContext:, − recordChangesInEditingContext

rollbackChanges

− (void)rollbackChanges

Overridden by subclasses to roll back changes to the underlying database. Raises one of several possible exceptions if an error occurs; the error message should indicate the nature of the problem.

See also:	 − commitChanges, − performChanges,

− saveChangesInEditingContext: (EOObjectStoreCoordinator)

valuesForKeys:object:

− (NSDictionary *)valuesForKeys:(NSArray *)keys object:(id)object

Overridden by subclasses to return values (as identified by keys) held by the receiver that augment properties in object. For instance, an EODatabaseContext stores foreign keys for the objects it owns (and primary keys for new objects). These foreign and primary keys may well not be defined as properties of the object. Other EODatabaseContexts can find out these keys by sending the EODatabaseContext that owns the object a valuesForKeys:object: message. Note that you use this for properties that are not stored in the object, so using key-value coding directly on the object won’t always work.


EODataSource

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	NSObject

Conforms To:	NSObject (NSObject)

Declared In:	EOControl/EODataSource.h

Class Description

EODataSource is an abstract class that defines a basic interface for providing enterprise objects. It exists primarily as a simple means for an EODisplayGroup or other higher-level class to access a store of objects. EODataSource defines functional implementations of very few methods; concrete subclasses, such as EODatabaseDataSource and EODetailDataSource, define working data sources by implementing the others. EODatabaseDataSource, for example, provides objects held by an EOEditingContext, while EODetailDataSource provides objects from a relationship property of a master object.

An EODataSource provides its objects all at once, with its fetchObjects method. insertObject: and deleteObject: add and remove individual objects, and createObject instantiates a new object. A few other methods provide more general information about the objects, as described below.

Creating a Subclass

The job of an EODataSource is to provide objects that share a set of properties, so that they can be managed uniformly by its client, such as an EODisplayGroup. Typically these objects are all of the same class, or share a superclass that defines the common properties managed by the client. All that’s needed, however, is that every object have the properties expected by the client. For example, if an EODataSource provides Member and Guest objects, they can be implemented as subclasses of a more general Customer class, or they can be independent classes defining the same properties (lastName, firstName, and address, for example). You typically specify the kind of objects an EODataSource provides when you initialize it. Subclasses usually define a special init... method whose arguments describe the objects. EODatabaseDataSource, for example, defines initWithEditingContext:entityName:, which uses an EOEntity to describe the set of objects. Another subclass might use an EOClassDescription, a class or superclass for the objects, or even a collection of existing instances.

A subclass can provide two other pieces of information about its objects, using methods declared by EODataSource. First, if your subclass keeps its objects in an EOEditingContext, it should override the editingContext method to return that EOEditingContext. It doesn’t have to use an EOEditingContext, though, in which case it can just use the default implementation of editingContext, which returns nil. Keep in mind, however, the amount of work EOEditingContexts do for you, especially when using EODisplayGroups. For example, EODisplayGroups depend on change notifications from EOEditingContexts to update changes in the objects displayed. If your subclass or its clients depend on change notification, you should use an EOEditingContext for object storage and change notification. If you don’t use one, you’ll have to implement that functionality yourself. For more information, see these class specifications:

EOObjectStore

EOEditingContext

EODisplayGroup

EODelayedObserverQueue

EODelayedObserver

The other piece of information—also optional—is an EOClassDescription for the objects. Interface Builder uses an EOClassDescription to get the keys it displays in its Connections Inspector, and EODataSource uses it by default when creating new objects. Your subclass should override classDescriptionForObjects to return the class description if it uses one and if it’s providing objects of a single superclass. Your subclass can either record an EOClassDescription itself, or get it from some other object, such as an EOEntity or from the objects it provides (through the added NSObject method classDescription). If it doesn’t use an EOClassDescription at all it can use the default implementation, which returns nil.

Manipulating Objects

A concrete subclass of EODataSource must at least provide objects by implementing fetchObjects. If it supports insertion of new objects, it should implement insertObject:, and if it supports deletion it should also implement deleteObject:. An EODataSource that implements its own store must define these methods from scratch. An EODataSource that uses another object as a store can forward these messages to that store. For example, an EODatabaseDataSource turns these three requests into objectsWithFetchSpecification:editingContext:, insertObject:, and deleteObject: messages to its EOEditingContext.

Implementing Master-Detail Data Sources

An EODataSource subclass can also implement a pair methods that allow it to be used in master-detail configurations. The first method, dataSourceQualifiedByKey:, should create and return a new data source, set up to provide objects of the destination class for a relationship in a master-detail setup. In a master-detail setup, changes to the detail apply to the objects in the master; for example, adding an object to the detail also adds it to the relationship of the master object. The standard EODetailDataSource class works well for this purpose, so you can simply implement dataSourceQualifiedByKey: to create and return one of these. Once you have a detail EODataSource, you can set the master object by sending the detail a qualifyWithRelationshipKey:ofObject: message. The detail then uses the master object in evaluating the relationship, and applies inserts and deletes to that master object.

Another kind of paired EODataSource setup, called master-peer, is exemplified by the EODatabaseDataSource class. In a master-peer setup, the two EODataSources are independent, so that changes to one don’t affect the other. Inserting into the “detail,” for example, has no effect on the master object. See that class description for more information.

Method Types

Getting the objects	− fetchObjects

Inserting and deleting objects	− createObject

− insertObject:

− deleteObject:

Creating detail EODataSources	− dataSourceQualifiedByKey:

− qualifyWithRelationshipKey:ofObject:

Getting the editing context	− editingContext

Getting the class description	− classDescriptionForObjects

Instance Methods

classDescriptionForObjects

− (EOClassDescription *)classDescriptionForObjects

Implemented by subclasses to return an EOClassDescription that provides information about the objects provided by the receiver. EODataSource’s implementation returns nil.

createObject

− (id)createObject

Creates a new object, inserts it in the receiver’s collection of objects if appropriate, and returns the object. Returns nil if the receiver can’t create the object or can’t insert it. You should invoke insertObject: after this method to actually add the new object to the receiver.

As a convenience, EODataSource’s implementation sends the receiver’s EOClassDescription a createInstanceWithEditingContext:globalID:zone: to create the object. If this succeeds and the receiver has an EOEditingContext, it sends the EOEditingContext an insertObject: message to register the new object with the EOEditingContext (note well that this does not insert the object into the EODataSource). Subclasses that don’t use EOClassDescriptions or EOEditingContexts should override this method without invoking super’s implementation.

See also:	− classDescriptionForObjects, − editingContext

dataSourceQualifiedByKey:

− (EODataSource *)dataSourceQualifiedByKey:(NSString *)relationshipKey

Implemented by subclasses to return a detail EODataSource that provides the destination objects of the relationship named by relationshipKey. The detail EODataSource can be qualified using qualifyWithRelationshipKey:ofObject: to set a specific master object (or to change the relationship key). EODataSource’s implementation merely raises an NSInvalidArgumentException; subclasses shouldn’t invoke super’s implementation.

deleteObject:

− (void)deleteObject:(id)anObject

Implemented by subclasses to delete anObject. EODataSource’s implementation merely raises an NSInvalidArgumentException; subclasses shouldn’t invoke super’s implementation.

editingContext

− (EOEditingContext *)editingContext

Implemented by subclasses to return the receiver’s EOEditingContext. EODataSource’s implementation returns nil.

fetchObjects

− (NSArray *)fetchObjects

Implemented by subclasses to fetch and return the objects provided by the receiver. EODataSource’s implementation returns nil.

insertObject:

− (void)insertObject:(id)object

Implemented by subclasses to insert anObject. EODataSource’s implementation merely raises an NSInvalidArgumentException; subclasses shouldn’t invoke super’s implementation.

qualifyWithRelationshipKey:ofObject:

− (void)qualifyWithRelationshipKey:(NSString *)key ofObject:(id)sourceObject

Implemented by subclasses to qualify the receiver, a detail EODataSource, to display destination objects for the relationship named key belonging to sourceObject. key should be the same as the key specified in the dataSourceQualifiedByKey: message that created the receiver. If sourceObject is nil, the receiver qualifies itself to provide no objects. EODataSource’s implementation merely raises an NSInvalidArgumentException; subclasses shouldn’t invoke super’s implementation.


EODelayedObserver

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	NSObject

Conforms To:	EODelayedObserving

NSObject (NSObject)

Declared In:	EOControl/EOObserver.h

Class Description

EODelayedObserver is an abstract superclass defining the basic functionality for coalescing change notifications for multiple objects and postponing notification according to a prioritized queue. See the EODelayedObserverQueue class specification for general information.

Creating a Subclass of EODelayedObserver

EODelayedObserver implements the basic objectWillChange: method to simply enqueue the receiver on an EODelayedObserverQueue. Regardless of how many of these messages the receiver gets during the run loop, it receives a single subjectChanged message from the queue—at the end of the run loop. In this method the EODelayedObserver can check for changes and take whatever action is necessary. Subclasses should record objects they’re interested in, perhaps in an init method, and examine them in subjectChanged. An EOAssociation, for example, examines each of the EODisplayGroups it’s bound to in order to find out what has changed. Another kind of subclass might record each changed object for later examination by overriding objectWillChange:, but it must be sure to invoke super’s implementation when doing so.

The rest of EODelayedObserver’s methods have meaningful, if static, default implementations. EODelayedObserverQueue sends change notifications according to the priority of each enqueued observer. EODelayedObserver’s priority method returns EOObserverPriorityThird. Your subclass can override it to return a higher or lower priority, or to have a settable priority. The other method a subclass might override is observerQueue, which returns a default EODelayedObserverQueue normally shared by all EODelayedObservers. Because sharing a single queue keeps all EODelayedObserver’s synchronized according to their priority, you should rarely override this method, doing so only if your subclass is involved in a completely independent system.

A final method, discardPendingNotification, need never be overridden by subclasses, but must be invoked from their implementation of dealloc. This prevents observers from being sent change notifications after they’ve been deallocated.

Adopted Protocols

EOObserving	− objectWillChange:

Method Types

Change notification	− subjectChanged

Canceling change notification	− discardPendingNotification

Getting the queue and priority	− observerQueue

− priority

Instance Methods

discardPendingNotification

− (void)discardPendingNotification

Sends a dequeueObserver: message to the receiver’s EODelayedObserverQueue to clear it from receiving a change notification. A subclass of EODelayedObserver should invoke this method in its implementation of dealloc.

See also:	− observerQueue

objectWillChange:

@protocol EOObserving

− (void)objectWillChange:(id)anObject

Implemented by EODelayedObserver to enqueue the receiver on its EODelayedObserverQueue. Subclasses shouldn’t need to override this method; if they do, they must be sure to invoke super’s implementation.

See also:	− observerQueue, − enqueueObject: (EODelayedObserverQueue)

observerQueue

− (EODelayedObserverQueue *)observerQueue

Overridden by subclasses to return the receiver’s designated EODelayedObserverQueue. EODelayedObserver’s implementation returns the default EODelayedObserverQueue.

See also:	+ defaultObserverQueue

priority

− (EOObserverPriority)priority

Overridden by subclasses to return the receiver’s change notification priority, one of:

EOObserverPriorityImmediate	EOObserverPriorityFourth

EOObserverPriorityFirst	EOObserverPriorityFifth

EOObserverPrioritySecond	EOObserverPrioritySixth

EOObserverPriorityThird	EOObserverPriorityLater

EODelayedObserver’s implementation returns EOObserverPriorityThird. See the EODelayedObserverQueue class specification for more information on priorities.

subjectChanged

− (void)subjectChanged

Implemented by subclasses to examine the receiver’s observed objects and take whatever action is necessary. EODelayedObserver’s implementation does nothing.


EODelayedObserverQueue

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	NSObject

Conforms To:	NSObject (NSObject)

Declared In:	EOControl/EOObserver.h

Class Description

EODelayedObserverQueue collects change notifications for observers of multiple objects and notifies them of the changes en masse during the application’s run loop, according to their individual priorities. This style of notification is particularly useful for coalescing and prioritizing multiple changes; the Interface layer’s EOAssociation classes use it extensively to update the user interface, for example. Instead of being told that an object will change, an EODelayedObserver is told that it did change, with a subjectChanged message, as described in the EODelayedObserver class specification. Delayed observation is thus not useful for comparing old and new states, but only for examining the new state.

The motivation for a delayed change notification mechanism arises mainly from issues in observing multiple objects. Any single change to an observed object typically requires the observer to update some state or perform an action. When many such objects change, it makes no sense to recalculate the new state and perform the action for each object. EODelayedObserverQueue allows these changes to be collected into a single notification. It further orders change notifications according to priorities, allowing observers to be updated in sequence according to dependencies among them. For example, an EOMasterDetailAssociation, which must update its detail EODisplayGroup according to the selection in the master before any redisplay occurs, has an earlier priority than the default for EOAssociations. This prevents regular EOAssociations from redisplaying old values and then displaying the new values after the EOMasterDetailAssociation updates.

Enqueuing a Delayed Observer

The enqueueObserver: method records an EODelayedObserver for later change notification. However, enqueuing is usually performed automatically by an EODelayedObserver in its objectWillChange: method. Hence, it’s typically enough that an object being observed invoke willChange as needed. An EODisplayGroup, for example, does this (among many other things) on receiving an objectsChangedInEditingContext: message from its EOEditingContext.

Although you can create individual EODelayedObserverQueues using alloc and init, you typically use the single instance provided by the defaultObserverQueue class method. Using separate queues bypasses the prioritization mechanism (described below), which may cause problems between the objects using the separate queues. If you do use separate queues, your EODelayedObserver subclasses should record a designated EODelayedObserverQueue that they always use, and implement observerQueue to return that object.

If you need to remove an enqueued observer, you can do so using the dequeueObserver: method. EODelayedObserver also defines the discardPendingNotification method, which removes the receiver from its designated queue. This is useful in an object’s implementation of dealloc, for example, to prevent a change notification being sent to it.

Change Notification

The actual process of change notification is initiated by the enqueueObserver: messages that line observers up to receive notifications. Regardless of how many times enqueueObserver: is invoked for a particular observer, that observer is only put in the queue once. The first observer enqueued during the run loop also triggers the EODelayedObserverQueue to set up a delayed invocation of notifyObserversUpToPriority:, which causes it to receive that message at the end of the run loop. EODelayedObserver sets up this delayed invocation in NSDefaultRunLoopMode, but you can change that using setRunLoopModes:.

notifyObserversUpToPriority: cycles through the queue of EODelayedObservers in priority order, from EOObserverPriorityFirst to the priority given, sending each observer a subjectChanged message. Each time, it returns to the earliest priority (rather than continuing through the queue) in case the message resulted in another EODelayedObserver with a earlier priority being enqueued. This guarantees an optimal delivery of change notifications.

Observer Proxies

It may not always be possible for a custom observer class to inherit from EODelayedObserver. To aid such objects in participating in delayed change notifications, the Framework defines the EOObserverProxy class, which implements its subjectChanged method to invoke an action method of your custom object. You create an EOObserverProxy using the initWithTarget:action:priority: method, which records the “real” observer, the action method to invoke, and the priority at which the EOObserverProxy should be enqueued. Then, instead of registering the custom object as an observer of objects, you register the proxy (using EOObserverCenter’s addObserver:forObject:). When it receives an objectWillChange: message, it enqueues itself for delayed change notification, receives the subjectChanged message from the EODelayedObserverQueue, and then sends the action message to the “real” observer.

Method Types

Creating instances	− init

Getting the default queue	+ defaultObserverQueue

Enqueuing and dequeuing observers	− enqueueObserver:

− dequeueObserver:

Sending change notifications	− notifyObserversUpToPriority:

Configuring notification behavior	− setRunLoopModes:

− runLoopModes

Class Methods

defaultObserverQueue

+ (EODelayedObserverQueue *)defaultObserverQueue

Returns the EODelayedObserverQueue that EODelayedObservers use by default.

Instance Methods

dequeueObserver:

− (void)dequeueObserver:(EODelayedObserver *)anObserver

Removes anObserver from the receiver.

See also:	− enqueueObserver:

enqueueObserver:

− (void)enqueueObserver:(EODelayedObserver *)anObserver

Records anObserver to be sent a subjectChanged message. If anObserver’s priority is EOObserverPriorityImmediate it’s immediately sent the message and not enqueued. Otherwise it’s sent the message the next time notifyObserversUpToPriority: is invoked with a priority later than or equal to anObserver’s. Does nothing if anObserver is already recorded.

The first time this method is invoked during the run loop with an observer whose priority isn’t EOObserverPriorityImmediate, it registers the receiver to be sent a notifyObserversUpToPriority: message at the end of the run loop, using EOFlushDelayedObserversRunLoopOrdering and the receiver’s run loop modes. This causes enqueued observers up to a priority of EOObserverPrioritySixth to be notified automatically during each pass of the run loop.

This method does not retain anObserver. When anObserver is deallocated, it should invoke dequeueObserver: to remove itself from the queue.

See also:	− dequeueObserver:, − priority (EODelayedObserver), − discardPendingNotification (EODelayedObserver), − runLoopModes, − performSelector:target:argument:order:modes: (NSRunLoop class of the Foundation Kit)

init

− (id)init

Initializes a newly allocated EODelayedObserverQueue with NSDefaultRunLoopMode as its only run loop mode. This is the designated initializer for the EODelayedObserverQueue class. Returns self.

notifyObserversUpToPriority:

− (void)notifyObserversUpToPriority:(EOObserverPriority)priority

Sends subjectChanged messages to all of the receiver’s enqueued observers whose priority is priority or earlier. This method cycles through the receiver’s enqueued observers in priority order, sending each a subjectChanged message and then returning to the very beginning of the queue, in case another observer with an earlier priority was enqueued as a result of the message.

EODelayedObserverQueue invokes this method automatically as needed during the run loop, with a priority of EOObserverPrioritySixth.

See also:	− enqueueObserver:, − priority (EODelayedObserver)

runLoopModes

− (NSArray *)runLoopModes

Returns the receiver’s run loop modes.

See also:	− setRunLoopModes:

setRunLoopModes:

− (void)setRunLoopModes:(NSArray *)modes

Sets the receiver’s run loop modes to modes.

See also:	− runLoopModes


EODetailDataSource

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	EODataSource : NSObject

Conforms To:	NSObject (NSObject)

Declared In:	EOControl/EODetailDataSource.h

Class Description

EODetailDataSource defines a data source for use in master-detail configurations, where operations in the detail data source are applied directly to properties of a master object. EODetailDataSource implements the standard fetchObjects, insertObject:, and deleteObject: methods to operate on a relationship property of its master object, so it works for any concrete subclass of EODataSource, including another EODetailDataSource (for a chain of three master and detail data sources).

To set up an EODetailDataSource programmatically, you typically create it by sending a dataSourceQualifiedByKey: message to the master data source, then establish the master object with a qualifyWithRelationshipKey:ofObject: message. The latter method records the name of a relationship for a particular object to resolve in fetchObjects, and to modify in insertObject:, and deleteObject:. These three methods then manipulate the relationship property of the master object to perform the operations requested. See the individual method descriptions for more information.

Method Types

Creating and qualifying instances	− initWithMasterDataSource:detailKey:

− qualifyWithRelationshipKey:ofObject:

Examining instances	− masterDataSource

− detailKey

− masterObject

Getting the objects	− fetchObjects

Inserting and deleting objects	− insertObject:

− deleteObject:

Instance Methods

deleteObject:

− (void)deleteObject:(id)anObject

Sends a removeObject:fromBothSidesOfRelationshipWithKey: message to the master object with anObject and the receiver’s detail key as the arguments. Raises an NSInternalInconsistencyException if there’s no master object or no detail key set.

See also:	− masterObject, − detailKey

detailKey

− (NSString *)detailKey

Returns the name of the relationship for which the receiver provides objects, as set in either initWithMasterDataSource:detailKey: or qualifyWithRelationshipKey:ofObject:. If none has been set yet, returns nil.

See also:	− masterObject

fetchObjects

− (NSArray *)fetchObjects

Sends valueForKey: to the master object with the receiver’s detail key as the argument, constructs an NSArray for the returned object or objects, and returns it. Returns an empty array if there’s no master object, or an array containing the master object itself if no detail key is set.

See also:	− masterObject, − detailKey

initWithMasterDataSource:detailKey:

− (id)initWithMasterDataSource:(EODataSource *)masterDataSource detailKey:(NSString *)relationshipKey

Initializes a newly allocated EODetailDataSource to provide objects based on a relationship of objects in masterDataSource named by relationshipKey. The receiver initially has no master object selected; to select one, use qualifyWithRelationshipKey:ofObject:.This is the designated initializer for the EODetailDataSource class. Returns self.

insertObject:

− (void)insertObject:(id)object

Sends an addObject:toBothSidesOfRelationshipWithKey: message to the master object with anObject and the receiver’s detail key as the arguments. Raises an NSInternalInconsistencyException if there’s no master object or no detail key set.

See also:	− masterObject, − detailKey

masterDataSource

− (EODataSource *)masterDataSource

Returns the receiver’s master data source.

See also:	− masterObject, − detailKey

masterObject

− (id)masterObject

Returns the object in the master data source for which the receiver provides objects. You can change this with a qualifyWithRelationshipKey:ofObject: message.

See also:	− masterDataSource, − detailKey

qualifyWithRelationshipKey:ofObject:

− (void)qualifyWithRelationshipKey:(NSString *)relationshipKey ofObject:(id)masterObject

Configures the receiver to provide objects based on the relationship of masterObject named by relationshipKey. relationshipKey can be different from the one used with initWithMasterDataSource:detailKey:, which changes the relationship for the receiver. If masterObject is nil, this method causes the receiver to return an empty array when sent a fetchObjects message.

See also:	− detailKey, − masterObject


EOEditingContext

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	EOObjectStore : NSObject

Conforms To:	EOObserving

Declared In:	EOControl/EOEditingContext.h

Purpose

EOEditingContext manages a graph of enterprise objects in an application; this object graph represents an internally consistent view of one or more external stores.

Principal Attributes

•	The set of enterprise objects managed by the EOEditingContext

•	The EOEditingContext’s parent EOObjectStore

•	The set of EOEditor objects managed by the EOEditingContext

•	The EOEditingContext’s message handler

Creation

− initWithParentObjectStore:	Designated initializer.

Commonly Used Methods

− objectsWithFetchSpecification:	Fetches objects from an external store.

− insertObject:	Registers a new object to be inserted into the parent EOObjectStore.

− deleteObject:	Registers that an object should be removed from the parent EOObjectStore when changes are saved.

− lockObject:	Attempts to lock an object in the external store.

− hasChanges	Returns YES if any of the receiver’s enterprise objects have been modified.

− saveChanges	Commits changes made in the receiver to the parent EOObjectStore.

− revert	Removes everything from the undo stack, discards all insertions and deletions, and restores updated objects to their original values.

− objectForGlobalID:	Given a globalID, returns its associated object.

− globalIDForObject:	Given an object, returns its globalID.

− setDelegate:	Sets the receiver’s delegate.

− delegate	Returns the receiver’s delegate.

− parentObjectStore	Returns the receiver’s parent EOObjectStore.

− rootObjectStore	Returns the receiver’s root EOObjectStore.

Class Description

EOEditingContext represents a single “object space” or document in an application. Its primary responsibility is managing a graph of enterprise objects. This object graph is a group of related business objects that represent an internally consistent view of one or more external stores.

All objects fetched from an external store are registered in an EOEditingContext along with a global identifier (EOGlobalID) that’s used to uniquely identify each object to the external store. The EOEditingContext is responsible for watching for changes in its objects (using the EOObserving protocol) and recording snapshots for object-based undo. A single enterprise object instance exists in one and only one EOEditingContext, but multiple copies of an object can exist in different EOEditingContexts. Thus object uniquing is scoped to a particular EOEditingContext.

Other Classes that Participate in Object Graph Management

EOEditingContext works in conjunction with other classes to manage the object graph. Two other classes that play a significant role in object graph management are EOUndoManager and EOObserverCenter. EOUndoManager is a general-purpose undo stack. As a client of EOUndoManager, EOEditingContext registers undo events for all changes made the enterprise objects that it watches.

The other class that plays a significant role in object graph management is EOObserverCenter. EOObserverCenter provides a notification mechanism for an observing object to find out when another object is about to change its state. “Observable” objects (typically all enterprise objects) are responsible for invoking [self willChange] prior to altering their state (in a “set” method, for instance). Objects (such as instances of EOEditingContext) can add themselves as observers to the objects they care about in the EOObserverCenter. They will then receive objectWillChange: notification whenever an observed object invokes [self willChange].

Using EOEditingContexts in Different Configurations

The fundamental relationship an EOEditingContext has is to its parent EOObjectStore, which creates the object graph the EOEditingContext monitors. EOObjectStore is an abstract class that defines a source and sink of objects for an EOEditingContext. The EOObjectStore is responsible for constructing and registering objects, servicing object faults, and committing changes made in an EOEditingContext.

You can augment the basic configuration of an EOEditingContext and its parent EOObjectStore in several different ways. For example, multiple EOEditingContexts can share the same EOObjectStore, one EOEditingContext can act as an EOObjectStore for another, and so on. The most commonly used scenarios are described in the following sections.

Peer EOEditingContexts

One or more “peer” EOEditingContexts can share a single EOObjectStore (Figure 1). Each EOEditingContext has its own object graph, so for example, a given Employee row in a database can have separate object instances in each EOEditingContext. Changes to an object in one EOEditingContext don’t affect the corresponding object in another EOEditingContext until all changes are successfully committed to the shared object store. At that time the objects in all EOEditingContexts are synchronized with the committed changes. This arrangement is useful when an application allows the user to edit multiple independent “documents.”

Figure 1 Peer EOEditingContexts

Nested EOEditingContexts

EOEditingContext is a subclass of EOObjectStore, which gives its instances the ability to act as EOObjectStores for other EOEditingContexts. In other words, EOEditingContexts can be nested (Figure 2), thereby allowing a user to make edits to an object graph in one EOEditingContext and then discard or commit those changes to another object graph (which, in turn, may commit them to an external store). This is useful in a “drill down” style of user interface where changes in a nested dialog can be okayed (committed) or canceled (rolled back) to the previous panel.

Figure 2 Nested EOEditingContexts

When an object is fetched into a nested EOEditingContext, it incorporates any uncommitted changes that were made to it in its parent EOEditingContext. For example, suppose that in one panel you have a list of employees that allows you to edit salaries, and that the panel includes a button to display a nested panel where you can edit detail information. If you edit the salary in the parent panel, you see the modified salary in the nested panel, not the old (committed) salary from the database. Thus, conceptually, nested EOEditingContexts fetch through their parents.

EOEditingContext overrides several of EOObjectStore’s methods:

− arrayFaultWithSourceGlobalID:relationshipName:editingContext:

− faultForGlobalID:editingContext:

− invalidateAllObjects

− objectsForSourceGlobalID:relationshipName:editingContext:

− objectsWithFetchSpecification:editingContext:

− propertiesForObjectWithGlobalID:editingContext:

− refaultObject:withGlobalID:editingContext:

− saveChangesInEditingContext:

These methods are generally used when an EOEditingContext acts as an EOObjectStore for another EOEditingContext. For more information, see the individual method descriptions. For information on setting up this configuration for interfaces loaded from nib files, see the method description for setDefaultParentObjectStore:.

Getting Data from Multiple Sources

An EOEditingContext’s object graph can contain objects from more than one external store (Figure 3). In this scenario, the object store is an EOObjectStoreCoordinator, which provides the abstraction of a single object store by redirecting operations to one or more EOCooperatingObjectStores.

Figure 3 An EOEditingContext Containing Objects from Multiple Sources

In writing an application, it’s likely that you’ll use combinations of the different scenarios described in the above sections.

Fetching Objects

The most common way to explicitly fetch objects from an external store in an Enterprise Objects Framework application is to use EOEditingContext’s objectsWithFetchSpecification: method. This method takes a fetch specification and returns an NSArray of objects. A fetch specification includes the name of the entity for which you want to fetch objects, the qualifier (query) you want to use in the fetch, and the sort order in which you want the objects returned (if any). For example, the following code excerpt uses objectsWithFetchSpecification: to fetch default values for rental terms from the database:

EOFetchSpecification *fetchSpec;

NSArray *results;

fetchSpec = [EOFetchSpecification

fetchSpecificationWithEntityName:@"RentalTerms"

qualifier:[EOQualifier qualifierWithQualifierFormat:@"rentalTermID = 1"]

sortOrderings:nil];

results = [editingContext objectsWithFetchSpecification:fetchSpec];

The Role of EOEditingContext in Change Management

An EOEditingContext is responsible for managing the changes that occur to the objects in its object graph. For example, when a user edits a value in the user interface, the following sequence of events occurs:

1.	The EOAssociation passes the new value to its EODisplayGroup.

2.	The EODisplayGroup applies the changes to the affected enterprise object.

3.	The enterprise object notifies the EOEditingContext that it has changed.

4.	Specifically, the enterprise object’s invocation of [self willChange] in turn invokes the EOEditingContext method objectWillChange:. objectWillChange: is part of the EOObserving protocol.

5.	The EOEditingContext records the object in its change list.

Then, at the end of the event loop:

6.	The EOEditingContext records undos.

7.	The EOEditingContext broadcasts an EOObjectsChangedInStoreNotification and an EOObjectsChangedInEditingContextNotification.

8.	EODisplayGroups receive the change notification and update the user interface.

9.	All views of the data in the application refresh themselves to reflect the change.

This sequence of events is illustrated in Figure 4.

Figure 4 Flow of Events When a User Edits Data

Saving Changes to the Database

The EOEditingContext is also involved when changes made to enterprise objects are saved to the database. Figure 5 illustrates the sequence of events:

Figure 5 Saving Changes to the Database

Managing Changes in Your Application

EOEditingContext provides several methods for managing the changes made to objects in your application. You can use these methods to get information about objects that have changed, to selectively undo and redo changes, and to discard all changes made to objects before these changes are committed to the database. These methods are described in the following sections.

Getting Information About Changed Objects

An EOEditingContext maintains information about three different kinds of changes to objects in its object graph: insertions, deletions, and updates. After these changes have been made and before they’re committed to the database, you can find out which objects have changes in each of these categories by using the insertedObjects, deletedObjects, and updatedObjects methods. Each method returns an NSArray containing the objects that have been inserted, deleted, and updated, respectively. The hasChanges method returns YES or NO to indicate whether any of the objects in the object graph have been inserted, deleted, or updated.

Undo and Redo

EOEditingContext includes the undo:, redo, and revert: methods for managing changes to objects in the object graph. undo: asks the EOEditingContext’s EOUndoManager to reverse the latest changes to objects in the object graph. redo: asks the EOUndoManager to reverse the latest undo operation. revert clears the undo stack, discards all insertions and deletions, and restores updated objects to their last committed (saved) values.

Refetching the Object Graph

You can use the refetch method to replace the values cached in memory (that is, in the object graph) with new values fetched from the database.

If you just want to discard uncommitted changes but you still want to maintain the values cached in memory, you should use revert instead.

Saving Changes

The saveChanges method commits changes made to objects in the object graph to an external store. When you save changes, EOEditingContext’s lists of inserted, updated, and deleted objects are flushed.

Upon a successful save operation, the EOEditingContext’s parent EOObjectStore broadcasts an EOObjectsChangedInStoreNotification. Peers of the saved EOEditingContext receive this notification and respond by synchronizing their objects with the committed versions.

Adopted Protocols

 EOObserving	− objectWillChange:

Method Types

Initializing an EOEditingContext	− initWithParentObjectStore:

Fetching objects	− objectsWithFetchSpecification:

Nested EOEditingContext support

− objectsWithFetchSpecification:editingContext:

− objectsForSourceGlobalID:relationshipName:editingContext:

− arrayFaultWithSourceGlobalID:relationshipName:editingContext:

− faultForGlobalID:editingContext:

− saveChangesInEditingContext:

− refaultObject:withGlobalID:editingContext:

− invalidateObjectWithGlobalID:

− initializeObject:withGlobalID:editingContext:

Committing or discarding changes	− saveChanges

− saveChanges:

− refaultObjects

− refault:

− refetch:

− revert

− revert:

− invalidateAllObjects

Object registration and snapshotting

− forgetObject:

− recordObject:globalID:

− committedSnapshotForObject:

− currentEventSnapshotForObject:

− objectForGlobalID:

− registeredObjects

− globalIDForObject:

Locking objects	− lockObject:

− lockObjectWithGlobalID:editingContext:

− isObjectLockedWithGlobalID:

− setLocksObjectsBeforeFirstModification:

− locksObjectsBeforeFirstModification

Registering changes	− deleteObject:

− insertObject:

− objectWillChange:

− processRecentChanges

Checking changes	− deletedObjects

− insertedObjects

− updatedObjects

− hasChanges

Undo	− redo:

− undo:

− undoManager

− setUndoManager:

Deletion and Validation Behavior	− setPropagatesDeletesAtEndOfEvent:

− propagatesDeletesAtEndOfEvent

− setStopsValidationAfterFirstError:

− stopsValidationAfterFirstError

Unarchiving from nib	+ defaultParentObjectStore

+ setDefaultParentObjectStore:

+ setSubstitutionEditingContext:

+ substitutionEditingContext

Returning related object stores	− parentObjectStore

− rootObjectStore

Managing editors	− editors

− addEditor:

− removeEditor:

Setting the delegate	− setDelegate:

− delegate

Setting the message handler	− setMessageHandler:

− messageHandler

Invalidating objects	− setInvalidatesObjectsWhenFreed:

− invalidatesObjectsWhenFreed

Class Methods

defaultParentObjectStore

+ (EOObjectStore *)defaultParentObjectStore

Returns the default parent EOObjectStore. Normally this is the EOObjectStoreCoordinator returned from the invocation [EOObjectStoreCoordinator defaultCoordinator].

See also:	+ setDefaultParentObjectStore:

setDefaultParentObjectStore:

+ (void)setDefaultParentObjectStore:(EOObjectStore *)store

Sets to store an EOEditingContext’s default parent EOObjectStore. You use this method before loading a nib file to change the default parent EOObjectStores of the EOEditingContexts in the nib file. The object you supply for store can be a different EOObjectStoreCoordinator or another EOEditingContext (if you’re using a nested EOEditingContext).

See also:	 + defaultParentObjectStore

setSubstitutionEditingContext:

+ (void)setSubstitutionEditingContext:(EOEditingContext *)anEditingContext

Sets to anEditingContext an EOEditingContext you want to substitute for the one specified in a nib file you’re about to load. Using this method causes all of the connections in your nib file to be redirected to anEditingContext. This can be useful when you want an interface loaded from a second nib file to use an existing EOEditingContext.

See also:	 + substitutionEditingContext

substitutionEditingContext

+ (EOEditingContext *)substitutionEditingContext

Returns the substitution EOEditingContext if one has been specified. Otherwise returns nil.

See also:	+ setSubstitutionEditingContext:

Instance Methods

addEditor:

− (void)addEditor:(id)editor

Adds to the receiver the EOEditor editor. For more explanation, see the method description for editors and the EOEditors informal protocol specification.

See also:	− editors, − removeEditor:

arrayFaultWithSourceGlobalID:relationshipName:editingContext:

− (NSArray *)arrayFaultWithSourceGlobalID:(EOGlobalID *)globalID relationshipName:(NSString *)name

editingContext:(EOEditingContext *)anEditingContext

Overrides EOObjectStore’s arrayFaultWithSourceGlobalID:relationshipName:editingContext: method. When a parent EOEditingContext receives this on behalf of a child EOEditingContext and the EOGlobalID globalID identifies a newly inserted object in the parent, the parent returns a copy of its object’s relationship NSArray with the member objects translated into objects in the child EOEditingContext. Otherwise, the EOEditingContext propagates this message to its parent EOObjectStore.

committedSnapshotForObject:

− (NSDictionary *)committedSnapshotForObject:(id)object

Returns an NSDictionary containing a snapshot of object that reflects its committed values (that is, its values as they were last committed to the database). In other words, this snapshot represents the state of the object before any modifications were made to it. The snapshot is updated to the newest object state after a save.

See also:	− currentEventSnapshotForObject:

currentEventSnapshotForObject:

− (NSDictionary *)currentEventSnapshotForObject:(id)object

Returns an NSDictionary containing a snapshot of object that reflects its state as it was at the beginning of the current event loop. After the end of the current event, this snapshot is updated to hold the modified state of the object.

See also:	− committedSnapshotForObject:

delegate

− (id)delegate

Returns the receiver’s delegate.

See also:	− setDelegate:

deleteObject:

− (void)deleteObject:(id)object

Specifies that object should be removed from the receiver’s parent EOObjectStore when changes are committed. At that time, the object will be removed from the uniquing tables.

See also:	− deletedObjects

deletedObjects

− (NSArray *)deletedObjects

Returns the objects that have been deleted from the receiver’s object graph.

See also:	− updatedObjects, − insertedObjects

editors

− (NSArray *)editors

Returns the receiver’s editors. Editors are special-purpose delegate objects that may contain uncommitted changes that need to be validated and applied to enterprise objects before the EOEditingContext saves changes. For example, EODisplayGroups register themselves as editors with the EOEditingContext of their data sources so that they can save any changes in the key text field. For more information, see the EOEditors informal protocol specification and the EODisplayGroup class specification.

See also:	− addEditor:, − removeEditor:

faultForGlobalID:editingContext:

− (id)faultForGlobalID:(EOGlobalID *)globalID

editingContext:(EOEditingContext *)anEditingContext

Overrides EOObjectStore’s faultForGlobalID:editingContext: method. If the object associated with the EOGlobalID globalID is already registered in the receiver, returns that object. Otherwise passes a request to the receiver’s parent EOObjectStore to create a to-one fault.

For example, suppose you want the department object whose deptID has a particular value. The most efficient way to get it is to look it up by its global ID using faultForGlobalID:editingContext::

EOEntity *entity = [[EOModelGroup defaultGroup] entityNamed:entityName];

EOGlobalID *gid = [entity globalIDForRow:[NSDictionary

 	dictionaryWithObjectsAndKeys:deptIdentifier, @"deptID", nil]];

return [editingContext faultForGlobalID:gid editingContext:editingContext];

If the object is already registered in the EOEditingContext, this code returns it (without going to the database). If not, a fault for this object is created, and when you touch the fault the object is fetched.

When a parent EOEditingContext is sent faultForGlobalID:editingContext: on behalf of a child EOEditingContext and globalID identifies a newly inserted object in the parent, the parent registers a copy of the object in the child. Otherwise, the EOEditingContext propagates this message to its parent EOObjectStore.

For more information on faults, see the EOObjectStore, EODatabaseContext, EOFault and EOFaultHandler class specifications.

forgetObject:

− (void)forgetObject:(id)object

Removes object from the uniquing tables and causes the receiver to remove itself as the object’s observer. This method is invoked whenever an object being observed by an EOEditingContext is deallocated. You generally should not invoke this method yourself.

globalIDForObject:

− (EOGlobalID *)globalIDForObject:object

Returns the EOGlobalID for object. All objects fetched from an external store are registered in an EOEditingContext along with a global identifier (EOGlobalID) that’s used to uniquely identify each object to the external store. If object hasn’t been registered in the EOEditingContext (that is, if no match is found), this method returns nil. Objects are registered in an EOEditingContext using the insertObject: method, or, when fetching, with recordObject:globalID:.

See also:	− objectForGlobalID:

hasChanges

− (BOOL)hasChanges

Returns YES if any of the objects in the receiver’s object graph have been modified—that is, if any objects have been inserted, deleted, or updated.

initWithParentObjectStore:

− initWithParentObjectStore:(EOObjectStore *)anObjectStore

Initializes the receiver with anObjectStore as its parent EOObjectStore. Returns self. This method is the designated initializer for EOEditingContext. For more discussion of parent EOObjectStores, see “Using EOEditingContexts in Different Configurations” in the class description.

initializeObject:withGlobalID:editingContext:

− (void)initializeObject:(id)object withGlobalID:(EOGlobalID *)globalID editingContext:(EOEditingContext *)anEditingContext

Overrides EOObjectStore’s initializeObject:withGlobalID:editingContext: to build the properties for the object identified by globalID. When a parent EOEditingContext receives this on behalf of a child EOEditingContext (as represented by anEditingContext), and the globalID identifies an object instantiated in the parent, the parent returns properties extracted from its object and translated into the child’s context. This ensures that a nested context “inherits” modified values from its parent EOEditingContext. If the receiver doesn’t have object, the request is fowarded the receiver’s parent EOObjectStore.

insertObject:

− (void)insertObject:(id)object

Registers object to be inserted in the receiver’s parent EOObjectStore the next time changes are saved. In the meantime, object is registered in the receiver with a temporary globalID.

See also:	− insertedObjects, − deletedObjects

insertedObjects

− (NSArray *)insertedObjects

Returns the objects that have been inserted into the receiver’s object graph.

See also:	− deletedObjects, − updatedObjects

invalidateAllObjects

− (void)invalidateAllObjects

Overrides the EOObjectStore method invalidateAllObjects to discard the values of objects cached in memory and refetch them from an external store.

See also:	− refetch:

invalidateObjectWithGlobalID:

− (void)invalidateObjectWithGlobalID:(EOGlobalID *)globalID

Signals to the parent EOObjectStore that the object identified by globalID should no longer be considered valid and that it should be refaulted. This message is propagated to any underlying EOObjectStore, resulting in a refetch the next time the object is accessed. Any child EOObjectStores are notified that the object is no longer valid.

invalidatesObjectsWhenFreed

− (BOOL)invalidatesObjectsWhenFreed

Returns YES to indicate that the receiver invalidates all of the objects registered with it when the receiver is deallocated, NO otherwise. The default is YES. For more discussion of this topic, see the method description for setInvalidatesObjectsWhenFreed:.

isObjectLockedWithGlobalID:

− (BOOL)isObjectLockedWithGlobalID:(EOGlobalID *)globalID

Returns YES if the object identified by globalID is locked, NO otherwise. This method works by forwarding the message isObjectLockedWithGlobalID: to its parent EOObjectStore.

See also:	− lockObject:, − lockObjectWithGlobalID:editingContext:,

− locksObjectsBeforeFirstModification, − setLocksObjectsBeforeFirstModification:

lockObject:

− (void)lockObject:(id)anObject

Attempts to lock anObject in the external store. This method works by invoking lockObjectWithGlobalID:editingContext:. Raises an NSInvalidArgumentException if it can’t find the globalID for anObject to pass to lockObjectWithGlobalID:editingContext:.

See also:	− isObjectLockedWithGlobalID:, − lockObjectWithGlobalID:editingContext:, − locksObjectsBeforeFirstModification, − setLocksObjectsBeforeFirstModification:

lockObjectWithGlobalID:editingContext:

− (void)lockObjectWithGlobalID:(EOGlobalID *)globalID

Overrides the EOObjectStore method lockObjectWithGlobalID:editingContext: to attempt to lock the object identified by globalID in the external store. Raises an NSInternalInconsistencyException if unable to obtain the lock. This method works by forwarding the message lockObjectWithGlobalID:editingContext: to its parent EOObjectStore.

See also:	− lockObject:, − isObjectLockedWithGlobalID:, − locksObjectsBeforeFirstModification,

− setLocksObjectsBeforeFirstModification:

locksObjectsBeforeFirstModification

− (BOOL)locksObjectsBeforeFirstModification

Returns YES if the receiver invokes [self lockObject:object] to lock object in the external store the first time object is modified.

See also:	− setLocksObjectsBeforeFirstModification:, − isObjectLockedWithGlobalID:, − lockObject:, − lockObjectWithGlobalID:editingContext:

messageHandler

− (id)messageHandler

Returns the EOEditingContext’s message handler. A message handler is a special-purpose delegate responsible for presenting errors to the user. Typically, an EODisplayGroup registers itself as the message handler for its EOEditingContext. For more information, see the EOMessageHandelers informal protocol specification.

See also:	− setMessageHandler:

objectForGlobalID:

− (id)objectForGlobalID:(EOGlobalID *)globalID

Returns the object identified by globalID, or nil if no object has been registered in the EOEditingContext with globalID.

See also:	− globalIDForObject:

objectsForSourceGlobalID:relationshipName:editingContext:

− (NSArray *)objectsForSourceGlobalID:(EOGlobalID *)globalID

relationshipName:(NSString *)name

editingContext:(EOEditingContext *)anEditingContext

Overrides EOObjectStore’s objectsForSourceGlobalID:relationshipName:editingContext: method to service a to-many fault for a relationship named name. When a parent EOEditingContext receives this on behalf of a child EOEditingContext and globalID matches an object instantiated in the parent, the parent returns a copy of its relationship NSArray and translates its objects into the child’s EOEditingContext. This ensures that a nested EOEditingContext “inherits” modified values from its parent EOEditingContext. If the receiving EOEditingContext does not have the specified object or if the parent’s relationship property is still an EOFault, the request is fowarded to its parent EOObjectStore.

objectsWithFetchSpecification:

− (NSArray *)objectsWithFetchSpecification:(EOFetchSpecification *)fetchSpecification

Invokes objectsWithFetchSpecification:editingContext: with self as the EOEditingContext and returns the result.

objectsWithFetchSpecification:editingContext:

− (NSArray *)objectsWithFetchSpecification:(EOFetchSpecification *)fetchSpecification editingContext:(EOEditingContext *)anEditingContext

Overrides EOObjectStore’s objectsWithFetchSpecification:editingContext: method to fetch objects from an external store according to the criteria specified by fetchSpecification and return them in an NSArray. If one of these objects is already present in memory, this method doesn’t overwrite its values with the new values from the database. This method raises an exception if an error occurs; the error message indicates the nature of the problem.

When an EOEditingContext receives this message, it forwards the message to its EOObjectStore (typically an EOObjectStoreCoordinator). Based on the entity name in fetchSpecification, the EOObjectStoreCoordinator in turn forwards the request to the appropriate EODatabaseContext. The EODatabaseContext then obtains an EODatabaseChannel and performs the fetch, registering all fetched objects in anEditingContext.

objectWillChange:

− (void)objectWillChange:(id)object

This method is automatically invoked when any of the objects registered in the receiver invokes [self willChange]. This method is EOEditingContext’s implementation of the EOObserving protocol.

parentObjectStore

− (EOObjectStore *)parentObjectStore

Returns the EOObjectStore from which the receiver fetches and to which it saves objects.

processRecentChanges

− (void)processRecentChanges

Forces the receiver to process pending insertions, deletions, and updates. Normally, when objects are changed, the processing of the changes is deferred until the end of the current event. At that point, an EOEditingContext moves objects to the inserted, updated, and deleted lists, delete propagation is performed, undos are registered, and EOObjectsChangedInStoreNotification and EOObjectsChangedInEditingContextNotification are posted (usually causing the user interface to update). You can use this method to explicitly force changes to be processed. An EOEditingContext automatically invokes this method on itself before performing certain operations such as saveChanges.

propagatesDeletesAtEndOfEvent

− (BOOL)propagatesDeletesAtEndOfEvent

Returns YES if the receiver propagates deletes at the end of the event in which a change was made, NO if it propagates deletes only right before saving changes. The default is YES.

See also:	− setPropagatesDeletesAtEndOfEvent:

recordObject:globalID:

− (void)recordObject:(id)object globalID:(EOGlobalID *)globalID

Makes the receiver aware of an object identified by globalID existing in its parent EOObjectStore. EOObjectStores (such as EODatabaseContext) usually invoke this method for each object fetched. When it receives this message, the receiver enters the object in its uniquing table and registers itself as an observer of the object.

redo:

− (void)redo:(id)sender

This action method forwards a redo message to the receiver’s EOUndoManager, asking it to reverse the latest undo operation applied to objects in the object graph.

See also:	− undo:

refault:

− (void)refault:(id)sender

This action method simply invokes refaultObjects.

refaultObjects

− (void)refaultObjects

Refaults all objects that haven’t been inserted, deleted, or updated.

refaultObject:withGlobalID:editingContext:

− (void)refaultObject:(id)anObject

withGlobalID:(EOGlobalID *)globalID

editingContext:(EOEditingContext *)anEditingContext

Overrides the EOObjectStore method refaultObject:withGlobalID:editingContext: to refault the enterprise object object identified by globalID in anEditingContext. This method should be used with caution since refaulting an object does not remove the object snapshot from the undo stack. Objects that have been newly inserted or deleted should not be refaulted.

refetch:

− (void)refetch:(id)sender

This action method tells the EOEditingContext to refetch. It does so by invoking the invalidateAllObjects method. This has the effect of discarding the values of objects cached in memory and refetching them from the external store. When an EOEditingContext receives this message, it propagates the message down the object store hierarchy. EODatabaseContexts discard their snapshots for invalidated objects and broadcast an EOObjectsChangedInStoreNotification.

The final effect of this method is to refault all objects currently in memory. This refaulting in turn releases all objects not retained by your application or by an EODisplayGroup.

If you just want to discard uncommitted changes but you don’t want to sacrifice the values cached in memory, use the EOEditingContext revert method, which reverses all changes and clears the undo stack.

registeredObjects

− (NSArray *)registeredObjects

Returns the enterprise objects managed by the receiver.

removeEditor:

− (void)removeEditor:(id)editor

Unregisters editor from the receiver. For more discussion of EOEditors, see the editors method description and the EOEditors informal protocol specification.

See also:	− addEditor:

revert

− (void)revert

Removes everything from the undo stack, discards all insertions and deletions, and restores updated objects to their last committed values. Does not refetch from the database. Note that revert doesn’t automatically cause EODisplayGroups to refetch. EODisplayGroups that allow insertion and deletion of objects need to be explicitly synchronized whenever this method is invoked on their EOEditingContext.

revert:

− (void)revert:(id)sender

 This action method simply invokes revert.

rootObjectStore

− (EOObjectStore *)rootObjectStore

Returns the non-EOEditingContext EOObjectStore at the base of the EOObjectStore hierarchy (usually an EOObjectStoreCoordinator).

saveChanges

− (void)saveChanges

Commits changes made in the receiver to its parent EOObjectStore by sending it the message saveChangesInEditingContext:. If the parent is an EOObjectStore Coordinator, it guides its EODatabaseContexts through a multi-pass save operation (see the EOObjectStoreCoordinator class specification for more information). If no message handler or delegate is available and a database error occurs, an exception is raised; the error message indicates the nature of the problem.

saveChanges:

− (void)saveChanges:(id)sender

This action method simply invokes saveChanges.

saveChangesInEditingContext:

− (void)saveChangesInEditingContext:(EOEditingContext *)anEditingContext

Overrides the EOObjectStore method saveChangesInEditingContext: to tell the receiver’s EOObjectStore to accept changes from a child EOEditingContext. This method shouldn’t be invoked directly. It’s invoked by a nested EOEditingContext when it’s committing changes to a parent EOEditingContext. The receiving parent EOEditingContext incorporates all changes from the nested EOEditingContext into its own copies of the objects, but it doesn’t immediately save those changes to the database. If the parent itself is later sent saveChanges, it propagates any changes received from the child along with any other changes to its parent EOObjectStore. Raises an exception if an error occurs; the error message indicates the nature of the problem.

setDelegate:

− (void)setDelegate:(id)anObject

 Set the receiver’s delegate to be anObject, without retaining it.

See also:	− delegate

setInvalidatesObjectsWhenFreed:

− (void)setInvalidatesObjectsWhenFreed:(BOOL)flag

Sets according to flag whether the receiver invalidates all of the objects registered with it when the receiver is deallocated. Sends clearProperties to all of its objects, thereby breaking any retain cycles between objects that would prevent them from being freed. “Invalidating” objects refers to leaving them in a state in which sending them any message other than dealloc or release raises an exception. The default is YES.

See also:	− invalidatesObjectsWhenFreed

setLocksObjectsBeforeFirstModification:

− (void)setLocksObjectsBeforeFirstModification:(BOOL)flag

Sets according to flag whether the receiver invokes [self lockObject:object] to lock object in the external store the first time object is modified. The default is NO. If flag is YES, an exception will be raised if a lock can’t be obtained when object invokes willChange.

See also:	− locksObjectsBeforeFirstModification

setMessageHandler:

− (void)setMessageHandler:(id)handler

Set the receiver’s message handler to be handler.

See also:	− messageHandler

setPropagatesDeletesAtEndOfEvent:

− (void)setPropagatesDeletesAtEndOfEvent:(BOOL)flag

Sets according to flag whether the receiver propagates deletes at the end of the event in which a change was made, or only just before saving changes.

If flag is YES, deleting an enterprise object triggers delete propagation at the end of the event in which the deletion occurred (this is the default behavior). If flag is NO, delete propagation isn’t performed until saveChanges: is invoked.

You can delete enterprise objects explicitly by using the deleteObject: method or implicitly by removing the enterprise object from an owning relationship. Delete propagation uses the delete rules in the EOClassDescription to determine whether objects related to the deleted object should also be deleted (for more information, see the EOClassDescription class specification). If delete propagation fails (that is, if an enterprise object refuses to be deleted—possibly due to a deny rule), all changes made during the event are rolled back.

See also:	− propagatesDeletesAtEndOfEvent

setStopsValidationAfterFirstError:

− (void)setStopsValidationAfterFirstError:(BOOL)flag

Sets according to flag whether the receiver stops validating after the first error is encountered, or continues for all objects (validation typically occurs during a save operation). The default is YES. Setting it to NO is useful if the delegate implements editingContext:shouldPresentException: to handle the presentation of aggregate exceptions.

See also:	− stopsValidationAfterFirstError

setUndoManager:

− (void)setUndoManager:(EOUndoManager *)undoManager

Sets the receiver’s EOUndoManager to undoManager.

See also:	− undoManager

stopsValidationAfterFirstError

− (BOOL)stopsValidationAfterFirstError

Returns YES to indicate that the receiver should stop validating after it encounters the first error, or NO to indicate that it should continue for all objects.

See also:	− setStopsValidationAfterFirstError:

undo:

− (void)undo:(id)sender

This action method forwards an undo message to the receiver’s EOUndoManager, asking it to reverse the latest uncommitted changes applied to objects in the object graph.

See also:	− redo:

undoManager

− (EOUndoManager *)undoManager

Returns the receiver’s EOUndoManager.

See also:	− setUndoManager:

updatedObjects

− (NSArray *)updatedObjects

Returns the objects in the receiver’s object graph that have been updated.

See also:	− deletedObjects, − insertedObjects

Methods Implemented By the Delegate

editingContext:shouldPresentException:

− (BOOL)editingContext:(EOEditingContext *)anEditingContext

shouldPresentException:(NSException *)exception

Sent whenever an exception is caught by an EOEditingContext. If the delegate returns NO, exception is ignored. Otherwise exception is passed to the message handler for further processing.

See also:	− messageHandler

editingContextShouldValidateChanges:

− (BOOL)editingContextShouldValidateChanges:(EOEditingContext *)anEditingContext

Sent when an EOEditingContext receives a saveChanges message. If the delegate returns NO, changes are saved without first performing validation. This method can be useful if the delegate wants to provide its own validation mechanism.

editingContextShouldSaveChanges:

− (BOOL)editingContextShouldSaveChanges:(EOEditingContext *)anEditingContext

Sent when an EOEditingContext receives a saveChanges message. If the delegate returns NO, the save operation is aborted.

editingContext:shouldInvalidateObject:globalID:

− (BOOL)editingContext:(EOEditingContext *)anEditingContext

shouldInvalidateObject:(id)object

globalID:(EOGlobalID *)globalID

Sent when an object identified by globalID has been explicitly invalidated. If the delegate returns NO, the invalidation is refused. This allows the delegate to selectively override object invalidations.

See also:	− invalidateAllObjects, − revert

editingContextShouldUndoUserActionsAfterFailure:

− (BOOL)editingContextShouldUndoUserActionsAfterFailure:(EOEditingContext *)context

Sent when a validation error occurs while processing a processRecentChanges message. If the delegate returns NO, it disables the automatic undoing of user actions after validation has resulted in an error.

By default, if a user attempts to perform an action that results in a validation failure (such as deleting a department object that has a delete rule stating that the department can’t be deleted if it contains employees), the user’s action is immediately rolled back. However, if this delegate method returns NO, the user action is allowed to stand (though attempting to save the changes to the database without solving the validation error will still result in a failure). Returning NO gives the user an opportunity to correct the validation problem so that the operation can proceed (for example, the user might delete all of the department’s employees so that the department itself can be deleted).

Notifications

The following notifications are declared (except where otherwise noted) and posted by EOEditingContext.

EOObjectsChangedInStoreNotification

Notification Object	The EOEditingContext

userInfo Dictionary

Key	Value

updated	An NSArray of EOGlobalIDs for objects whose properties have

changed. A receiving EOEditingContext typically responds by

refaulting the objects.

inserted	An NSArray of EOGlobalIDs for objects that have been inserted

into the EOObjectStore.

deleted	An NSArray of EOGlobalIDs for objects that have been deleted

from the EOObjectStore.

invalidated	An NSArray of EOGlobalIDs for objects that have been turned

into EOFaults. Invalidated objects are those for which the

cached view can should no longer be trusted. Invalidated objects

 	should be refaulted so that they are refetched when they’re next

 	examined.

This notification is broadcast whenever objectWillChange observer notifications are processed, which is usually as the end of the event in which the changes occurred. EODisplayGroups listen for this notification to redisplay their contents. See the EOObjectStore class specification for more information on EOObjectsChangedInStoreNotification.

EOObjectsChangedInEditingContextNotification

Notification Object	The EOEditingContext

userInfo Dictionary

Key	Value

updated	An NSArray containing the changed objects

deleted	An NSArray containing the deleted objects

inserted	An NSArray containing the inserted objects

invalidated	An NSArray containing invalidated objects.

This notification is broadcast is broadcast whenever changes are made in an EOEditingContext. EOObjectsChangedInEditingContextNotification is similar to EOObjectsChangedInStoreNotification, except that it contains objects rather than global ID’s.

EOEditingContextDidSaveChangesNotification

Notification Object	The EOEditingContext

userInfo Dictionary	None.

This notification is broadcast after changes are saved to the EOEditingContext’s parent EOObjectStore.

EOInvalidatedAllObjectsInStoreNotification

Notification Object	The EOEditingContext

userInfo Dictionary	None.

This notification is broadcast whenever an EOEditingContext is invalidating all its objects. When an EOEditingContext receives this notification from its parent EOObjectStore, it clears its lists of inserted, updated, and deleted objects, and resets its undo stack. EODisplayGroups listen for this notification to refetch their contents. See the EOObjectStore class specification for more information on this notification.


EOEditors

(informal protocol)

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Category Of:	NSObject

Declared In:	EOControl/EOEditingContext.h

Category Description

EOEditingContext defines this category of NSObject for objects that act as higher-level editors of the objects it contains. An EOEditingContext sends messages to its editors to determine whether they have any changes that need to be saved, and to allow them to flush pending changes before a save (possibly raising an exception to abort the save). See the EOEditingContext and EODisplayGroup class specifications for more information.

Instance Methods

editingContextWillSaveChanges:

− (void)editingContextWillSaveChanges:(EOEditingContext *)anEditingContext

Invoked by anEditingContext in its saveChanges method, this method allows the receiver to prohibit a save operation. The receiver should validate any unprocessed edits it has, raising an exception if it can’t do so to prevent anEditingContext from saving. This method is declared, but not implemented by NSObject.

editorHasChangesForEditingContext:

− (BOOL)editorHasChangesForEditingContext:(EOEditingContext *)anEditingContext

Invoked by anEditingContext, this method should return YES if the receiver has any unprocessed edits that need to be saved, NO if it doesn’t. This method is declared, but not implemented by NSObject.


EOFault

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	none (EOFault is a root class)

Declared In:	EOControl/EOFault.h

Class Description

EOFault and EOFaultHandler form a general mechanism for substituting placeholder objects that convert themselves into regular objects. An EOFault is most commonly used by the Access Layer to represent an object not yet fetched from the database, but that must nonetheless exist as an instance in the application—typically because it’s the destination of a relationship. EOFault is a completely general class; there’s no need to create subclasses to customize fault handling. Instead, you create subclasses of EOFaultHandler to accommodate different means of converting faults into regular objects.

The faulting mechanism provides for continuity of an object’s id even when that object’s state isn’t yet available. An EOFault simply holds the place for an ultimate “real” object, handling all methods that it can without causing the state to be loaded. When an EOFault receives a message that it can’t handle, it calls upon its EOFaultHandler to fire it, converting it into a “real” object. This often involves accessing the external, persistent state of the object.

Creating an EOFault

Rather than allocating and initializing an EOFault, you turn an existing object into one using EOFault’s makeObjectIntoFault:withHandler: class method. When you do so, you must provide an EOFaultHandler that will later help the fault to fire. makeObjectIntoFault:withHandler: preserves the id of the original object, overlaying its isa pointer with that of the EOFault class and slipping the EOFaultHandler among its instance variables. Once this is done, the original object is an EOFault that will fire when accessed.

The EOFaultHandler should be considered completely private property of the EOFault once you’ve created it. You should neither retain the EOFaultHandler or send it any other messages, instead dealing exclusively with the newly created EOFault or the EOFault class itself.

EOFault Behavior

EOFault implements many basic object methods in a manner that doesn’t cause the receiver to fire. The following methods all behave as though normal for the original object:

− retain	− isMemberOfClass:

− release	− conformsToProtocol:

− autorelease	− isProxy

− retainCount	− methodSignatureForSelector:

− class	− respondsToSelector:

− superclass	− zone

− isKindOfClass:	− doesNotRecognizeSelector:

doesNotRecognizeSelector: is a special case here, in that it’s only invoked if the selector in question isn’t found for the original class. Normally, methods not implemented by EOFault, but implemented by the original class, cause the receiver to fire as described below.

These methods don’t cause the receiver to fire, but also don’t hide the presence of the EOFault class:

− description	− descriptionWithLocale:

− descriptionWithIndent:	− descriptionWithLocale:indent:

− eoDescription	− eoShallowDescription

The following common methods, along with any others not explicitly mentioned in this section, do cause the receiving EOFault to fire.

− dealloc

− self

− forwardInvocation:

When an EOFault receives one of these messages, it fires in one of a few different ways. dealloc invokes the clearFault: class method to revert the receiver back to its original state, then reinvokes dealloc to clean up instance variables and deallocate the object. The other methods all send a special message, completeInitializationOfObject:, to the EOFaultHandler to transform the EOFault into a regular object, possibly different from its original state. In addition, forwardInvocation: sends a shouldPerformInvocation: to the EOFaultHandler first, which allows it to perform the method itself without causing the EOFault to be transformed. If the EOFaultHandler returns YES, though, the EOFault then sends it a completeInitializationOfObject: message.

Examining an EOFault

Three additional EOFault methods allow you to explicitly check whether an object is an EOFault without causing it to fire, and to get its original class and EOFaultHandler if it is an EOFault. These methods are:

+ isFault:

+ targetClassForFault:

+ handlerForFault:

You can use these methods to base some decisions on whether an object is an EOFault, though you should rarely need to do so.

Method Types

Creating and examining faults	+ makeObjectIntoFault:withHandler:

+ isFault:

+ clearFault:

+ handlerForFault:

+ targetClassForFault:

+ respondsToSelector:

Checking class information	− class

− isKindOfClass:

− isMemberOfClass:

− respondsToSelector:

− conformsToProtocol:

− methodSignatureForSelector:

Run-time support	− forwardInvocation:

− doesNotRecognizeSelector:

Getting a fault’s description	− description

− descriptionWithIndent:

− descriptionWithLocale:

− descriptionWithLocale:indent:

− eoDescription

− eoShallowDescription

Reference-counting	− retain

− release

− retainCount

− autorelease

− dealloc

Miscellaneous object methods	− self

− isProxy

− superclass

− zone

Class Methods

clearFault:

+ (void)clearFault:(id)aFault

Restores aFault to its status prior to the makeObjectInfoFault:withHandler: message that created it. Raises an NSInvalidArgumentException if aFault isn’t an EOFault.

You rarely use this method. Faults typically fire automatically when accessed, using EOFaultHandler’s completeInitializationOfObject: method. See the EOFaultHandler class specification for more information.

handlerForFault:

+ (EOFaultHandler *)handlerForFault:(id)aFault

Returns the EOFaultHandler that will help aFault to fire. Returns nil if aFault isn’t an EOFault.

isFault:

+ (BOOL)isFault:(id)anObject

Returns YES if anObject is an EOFault, NO otherwise.

makeObjectIntoFault:withHandler:

+ (void)makeObjectIntoFault:(id)anObject withHandler:(EOFaultHandler *)aFaultHandler

Converts anObject into an EOFault, assigning aFaultHandler as the object that stores its original state and later converts the EOFault back into a normal object (typically by fetching data from an external repository). The new EOFault becomes the owner of aFaultHandler; you shouldn’t assign it to another object.

respondsToSelector:

+ (BOOL)respondsToSelector:(SEL)aSelector

Returns YES if the receiving class responds to aSelector, NO otherwise.

targetClassForFault:

+ (Class)targetClassForFault:(id)aFault

Returns the original class of the object that was turned into aFault, or nil if aFault isn’t an EOFault. When the EOFault fires, it’s guaranteed to be an instance of this class or possibly of a subclass. To get the actual class, you must send a class message to the EOFault, which may fire to determine its actual class membership.

Instance Methods

autorelease

− (id)autorelease

Performs as NSObject’s autorelease method.

class

− (Class)class

Returns the class of the object that the receiving EOFault will become. This may cause the EOFault to fire in order to determine its actual class membership.

See also:	− classForFault: (EOFaultHandler), + targetClassForFault:

conformsToProtocol:

− (BOOL)conformsToProtocol:(Protocol *)aProtocol

Returns YES if the object that the receiving EOFault will become conforms to aProtocol, NO if it doesn’t. This may cause the EOFault to fire in order to determine its actual class membership.

See also:	− conformsToProtocol:forFault: (EOFaultHandler)

dealloc

− (void)dealloc

Invokes the clearFault: class method to revert the receiving EOFault to its original class membership and state, then reinvokes dealloc.

description

− (NSString *)description

Sends descriptionForObject: to the receiver’s EOFaultHandler and returns the result.

descriptionWithIndent:

− (NSString *)descriptionWithIndent:(unsigned int)indentLevel

Invokes description and returns the result.

descriptionWithLocale:

− (NSString *)descriptionWithLocale:(NSDictionary *)locale

Invokes description and returns the result.

descriptionWithLocale:indent:

− (NSString *)descriptionWithLocale:(NSDictionary *)locale indent:(unsigned)indentLevel

Invokes description and returns the result.

doesNotRecognizeSelector:

− (void)doesNotRecognizeSelector:(SEL)aSelector

Raises an NSInvalidArgumentException.

eoDescription

− (NSString *)eoDescription

Invokes description and returns the result.

See also:	− eoDescription (NSObject Additions)

eoShallowDescription

− (NSString *)eoShallowDescription

Invokes description and returns the result.

See also:	− eoShallowDescription (NSObject Additions)

forwardInvocation:

− (void)forwardInvocation:(NSInvocation *)anInvocation

Causes the receiving EOFault to fire, if allowed by its EOFaultHandler, and forward anInvocation to its new incarnation. Sends a shouldPerformInvocation: to the receiver’s EOFaultHandler first, giving it a chance to bypass the conversion. If the EOFaultHandler returns NO, returns immediately. If it returns YES, sends a completeInitializationOfObject: message to the EOFaultHandler with self as the argument. Once the receiver has fired it invokes anInvocation.

isKindOfClass:

− (BOOL)isKindOfClass:(Class)aClass

Returns YES if aClass is the class, or a superclass, of the object that the receiving EOFault will become, NO otherwise. This may cause the EOFault to fire in order to determine its actual class membership.

See also:	− isMemberOfClass:, − isKindOfClass:forFault: (EOFaultHandler)

isMemberOfClass:

− (BOOL)isMemberOfClass:(Class)aClass

Returns YES if aClass is the class of the object that the receiving EOFault will become, NO otherwise. This may cause the EOFault to fire in order to determine its actual class membership.

See also:	− isKindOfClass:, − isMemberOfClass:forFault: (EOFaultHandler)

isProxy

− (BOOL)isProxy

Returns NO.

methodSignatureForSelector:

− (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector

Returns a method signature for aSelector for the object that the receiving EOFault will become, or nil if one can’t be found. This may cause the EOFault to fire in order to determine its actual class membership.

See also:	− methodSignatureForSelector:forFault: (EOFaultHandler)

release

− (void)release

Performs as NSObject’s release method.

respondsToSelector:

− (BOOL)respondsToSelector:(SEL)aSelector

Returns YES if the object that the receiving EOFault will become responds to aSelector, NO otherwise. This may cause the EOFault to fire in order to determine its actual class membership.

See also:	− respondsToSelector:forFault: (EOFaultHandler)

retain

− (id)retain

Performs as NSObject’s retain method.

retainCount

− (unsigned int)retainCount

Performs as NSObject’s retainCount method.

self

− (id)self

Fires the receiver and returns self. This is the recommended way to simply fire an EOFault.

superclass

− (Class)superclass

Returns the superclass of the object that the receiving EOFault will become. This may cause the EOFault to fire in order to determine its actual class membership.

See also:	− classForFault: (EOFaultHandler)

zone

− (NSZone *)zone

Performs as NSObject’s zone method.


EOFaultHandler

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	NSObject

Conforms To:	NSObject (NSObject)

Declared In:	EOControl/EOFault.h

Class Description

EOFaultHandler is the abstract class defining the mechanism that helps an EOFault to fire. Subclasses of EOFaultHandler perform the specific steps necessary to get data for the EOFault and fire it. The Access layer, for example, uses private subclasses to fetch data using an EODatabaseContext. Most of EOFaultHandler’s methods are properly defined; you need only override completeInitializationOfObject: to provide appropriate behavior. In addition, however, you can optionally implement faultWillFire: to prepare for conversion, and shouldPerformInvocation: to intercept particular messages sent to the EOFault without causing it to fire.

You create an EOFaultHandler using the standard alloc and init methods, possibly using a more specific init method with your subclass. To create an EOFault, you invoke EOFault’s makeObjectIntoFault:withHandler: class method with the object to turn into an EOFault and the EOFaultHandler. An EOFaultHandler belongs exclusively to a single EOFault, and shouldn’t be shared or used by any other object.

Firing an EOFault

When an EOFault receives a message that requires it to fire, it sends a completeInitializationOfObject: method to its EOFaultHandler. This method is responsible for invoking EOFault’s clearFault: class method to revert the EOFault to its original state, and then do whatever is necessary to complete initialization of the object. Doing so typically involves fetching data from an external repository and passing it to the object.

As a trivial example, consider a subclass called FileFaultHandler, that simply stores a filename whose contents it reads from disk. Its initialization and completeInitializationOfObject: methods might look like these:

- (id)initWithFile:(NSString *)path

{

    self = [super init];

    filename = [path copy];

    return self;

}

- (void)completeInitializationOfObject:(id)anObject

{

    NSString *fileContents;

    [EOFault clearFault:anObject];

    // This releases self; be sure to retain if needed!

    fileContents = [NSString stringWithContentsOfFile:filename];

    [anObject takeValue:fileContents forKey:@"fileContents"];

    return;

}

initWithFile: just stores the path of the file to read in the instance variable filename. completeInitializationOfObject: invokes EOFault’s clearFault: method, which reverts the EOFault into its original state (and also releases the fault handler, so references to self after this are illegal). It then gets the contents of the file it was created with and passes them to the reverted object. Note that this implementation doesn’t assume the class of the cleared EOFault, instead using the generic takeValue:forKey: method to assign the file contents to it.

Method Types

Setting the target class and extra data	− setTargetClass:extraData:

− targetClass

− extraData

Reference counting	− incrementExtraRefCount

− decrementExtraRefCountWasZero

− extraRefCount

Getting the original class	− classForFault:

Firing a fault	− completeInitializationOfObject:

− faultWillFire:

− shouldPerformInvocation:

Getting a description	− descriptionForObject:

Checking class information	− isKindOfClass:forFault:

− isMemberOfClass:forFault:

− conformsToProtocol:forFault:

− methodSignatureForSelector:forFault:

− respondsToSelector:forFault:

Instance Methods

classForFault:

− (Class)classForFault:(id)aFault

Returns the target class of the receiver’s EOFault, which must be passed as aFault in case the receiver needs to fire it (EOFaultHandlers don’t store back pointers to their EOFaults). For example, to support entity inheritance, the Access layer fires EOFaults for entities with subentities to confirm their precise class membership.

See also:	− completeInitializationOfObject:

completeInitializationOfObject:

− (void)completeInitializationOfObject:(id)aFault

Implemented by subclasses to revert aFault to its original state and complete its initialization in whatever means is appropriate to the subclass. For example, the Access layer subclasses of EOFaultHandler fetch data from the database and pass it to the object. This method is invoked automatically by an EOFault when it’s sent a message that it can’t handle without reverting to its original class. EOFaultHandler’s implementation merely raises an exception.

conformsToProtocol:forFault:

− (BOOL)conformsToProtocol:(Protocol *)aProtocol forFault:(id)aFault

Returns YES if the target class of the receiver’s EOFault conforms to aProtocol. This EOFault must be passed as aFault in case the receiver needs to fire it (EOFaultHandlers don’t store back pointers to their EOFaults). For example, to support entity inheritance, the Access layer fires EOFaults for entities with subentities to confirm their precise class membership.

See also:	− completeInitializationOfObject:

decrementExtraRefCountWasZero

− (BOOL)decrementExtraRefCountWasZero

Used by EOFaultHandler’s internal reference counting mechanism, this method functions as the Foundation function NSDecrementExtraRefCountWasZero() for the receiver’s EOFault.

descriptionForObject:

− (NSString *)descriptionForObject:(id)aFault

Returns a string naming the original class of the receiver’s EOFault and giving aFault’s id, and also noting that it’s a fault; for example: “<Employee (Fault 0x3a07)>”. (The EOFault must be passed as aFault because EOFaultHandlers don’t store back pointers to their EOFaults.)

extraData

− (void *)extraData

Returns the bytes replaced by the receiver’s id in the original object’s state, as a pointer to void. When the receiver’s EOFault is reverted to its original state, both its isa pointer and this data are replaced.

extraRefCount

− (unsigned int)extraRefCount

Used by EOFaultHandler’s internal reference counting mechanism, this method functions as the Foundation function NSExtraRefCount() for the receiver’s EOFault.

faultWillFire:

− (void)faultWillFire:(id)aFault

Invoked from EOFault’s clearFault: method to inform the receiver that aFault is about to be reverted to its original state. EOFaultHandler’s implementation does nothing.

incrementExtraRefCount

− (void)incrementExtraRefCount

Used by EOFaultHandler’s internal reference counting mechanism, this method functions as the Foundation function NSIncrementExtraRefCount() for the receiver’s EOFault.

isKindOfClass:forFault:

− (BOOL)isKindOfClass:(Class)aClass forFault:(id)aFault

Returns YES if the target class of the receiver’s EOFault is aClass or a subclass of aClass. This EOFault must be passed as aFault in case the receiver needs to fire it (EOFaultHandlers don’t store back pointers to their EOFaults). For example, to support entity inheritance, the Access layer fires EOFaults for entities with subentities to confirm their precise class membership.

See also:	− completeInitializationOfObject:

isMemberOfClass:forFault:

− (BOOL)isMemberOfClass:(Class)aClass forFault:(id)aFault

Returns YES if the target class of the receiver’s EOFault is aClass. This EOFault must be passed as aFault in case the receiver needs to fire it (EOFaultHandlers don’t store back pointers to their EOFaults). For example, to support entity inheritance, the Access layer fires EOFaults for entities with subentities to confirm their precise class membership.

See also:	− completeInitializationOfObject:

methodSignatureForSelector:forFault:

− (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector forFault:(id)aFault

Returns the NSMethodSignature for aSelector in the target class of the receiver’s EOFault, which must be passed as aFault in case the receiver needs to fire it (EOFaultHandlers don’t store back pointers to their EOFaults). For example, to support entity inheritance, the Access layer fires EOFaults for entities with subentities to confirm their precise class membership.

See also:	− completeInitializationOfObject:

respondsToSelector:forFault:

− (BOOL)respondsToSelector:(SEL)aSelector forFault:(id)aFault

Returns YES if the target class of the receiver’s EOFault responds to aSelector. This EOFault must be passed as aFault in case the receiver needs to fire it (EOFaultHandlers don’t store back pointers to their EOFaults). For example, to support entity inheritance, the Access layer fires EOFaults for entities with subentities to confirm their precise class membership.

See also:	− completeInitializationOfObject:

setTargetClass:extraData:

− (void)setTargetClass:(Class)targetClass extraData:(void *)extraData

Stores targetClass and extraData as state of the original object overwritten when an EOFault is created by EOFault’s makeObjectIntoFault:withHandler: method, which replaces targetClass with the EOFault class, and extraData with the EOFaultHandler’s id.

shouldPerformInvocation:

− (BOOL)shouldPerformInvocation:(NSInvocation *)anInvocation

Overridden by subclasses to circumvent reversion of an EOFault to its original state. Returns YES if the EOFault should revert and perform anInvocation, NO if it shouldn’t. If this method returns NO, the receiver should set anInvocation’s return value appropriately. EOFaultHandler’s implementation returns YES.

See also:	− setReturnValue: (NSInvocation class of the Foundation Framework)

targetClass

− (Class)targetClass

Returns the target class of the receiver’s EOFault. The EOFault may, however, be converted to a member of this class or of a subclass of this class. For example, to support entity inheritance, the Access layer fires EOFaults for entities with subentities into the appropriate class on fetching their data.


EOFetchSpecification

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	NSObject

Conforms To:	NSCopying

NSObject (NSObject)

Declared In:	EOControl/EOFetchSpecification.h

Class Description

An EOFetchSpecification collects the criteria needed to select and order a group of records or enterprise objects, whether from an external repository such as a relational database or an internal store such as an EOEditingContext. An EOFetchSpecification contains these elements:

•	The name of an entity for which to fetch records or objects. This is the only mandatory element.

•	An EOQualifier, indicating which properties to select by and how to do so.

•	An array of EOSortOrderings, which indicate how the selected records or objects should be ordered when fetched.

•	An indicator of whether to produce distinct results or not. Normally if a record or object is selected several times, such as when forming a join, it appears several times in the fetched results. An EOFetchSpecification that makes distinct selections causes duplicates to be filtered out, so that each record or object selected appears exactly once in the result set.

•	An indicator of whether to fetch deeply or not. This is used with inheritance hierarchies when fetching for an entity with sub-entities. A deep fetch produces all instances of the entity and its sub-entities, while a shallow fetch produces instances only of the entity in the fetch specification.

•	A dictionary of hints, which an EODatabaseContext or other object can use to optimize or alter the results of the fetch.

EOFetchSpecifications are used most often in the objectsWithFetchSpecification:editingContext: method defined by EOObjectStore, EOEditingContext, and EODatabaseContext, as well as objectsWithFetchSpecification:, defined by EOEditingContext alone. EOAdaptorChannel and EODatabaseChannel also define methods that use EOFetchSpecifications.

Adopted Protocols

NSCopying	− copyWithZone:

Method Types

Creating instances	+ fetchSpecificationWithEntityName:qualifier:sortOrderings:

− init

− initWithEntityName:qualifier:sortOrderings:usesDistinct:

isDeep:hints:

Configuring fetch parameters	− setEntityName:

− entityName

− setQualifier:

− qualifier

− setSortOrderings:

− sortOrderings

− setUsesDistinct:

− usesDistinct

− setLocksObjects:

− locksObjects

− setIsDeep:

− isDeep

− setRefreshesRefetchedObjects:

− refreshesRefetchedObjects

− setHints:

− hints

Class Methods

fetchSpecificationWithEntityName:qualifier:sortOrderings:

+ (EOFetchSpecification *)fetchSpecificationWithEntityName:(NSString *)entityName

qualifier:(EOQualifier *)qualifier

sortOrderings:(NSArray *)sortOrderings

Returns an EOFetchSpecification for entityName, using qualifier to select and sortOrderings to sort the results. This EOFetchSpecification doesn’t perform distinct selection, is deep, and has no hints.

See also:	− initWithEntityName:qualifier:sortOrderings:usesDistinct:isDeep:hints:

Instance Methods

entityName

− (NSString *)entityName

Returns the name of the entity to be fetched.

See also:	− isDeep, − setEntityName:

hints

− (NSDictionary *)hints

Returns the receiver’s hints, which other objects can use to alter or optimize fetch operations. EODatabaseContext’s objectsWithFetchSpecification:editingContext: uses a hint to prefetch the destinations of relationships, for example. See the EODatabaseContext class specification for more information.

See also:	− setHints:

init

− (id)init

Initializes a new EOFetchSpecification with no state, except that it fetches deeply and doesn’t use distinct. Use the set... methods to add other parts of the specification. This is the designated initializer for the EOFetchSpecification class. Returns self.

See also:	− initWithEntityName:qualifier:sortOrderings:usesDistinct:isDeep:hints:

initWithEntityName:qualifier:sortOrderings:usesDistinct:isDeep:hints:

− (id)initWithEntityName:(NSString *)entityName

qualifier:(EOQualifier *)qualifier

sortOrderings:(NSArray *)sortOrderings

usesDistinct:(BOOL)distinctFlag

isDeep:(BOOL)deepFlag

hints:(NSDictionary *)hints

Initializes a new EOFetchSpecification with the given arguments. Returns self.

See also:	+ fetchSpecificationWithEntityName:qualifier:sortOrderings:

isDeep

− (BOOL)isDeep

Returns YES if a fetch should include sub-entities of the receiver’s entity, NO if it shouldn’t. EOFetchSpecifications are deep by default.

For example, if you have a Person entity with two sub-entities, Employee and Customer, fetching Persons deeply also fetches all Employees and Customers matching the qualifier, and fetching Persons shallowly fetches only Persons matching the qualifier.

See also:	− setIsDeep:

locksObjects

− (BOOL)locksObjects

Returns YES if a fetch should result in the selected objects being locked in the data repository, NO if it shouldn’t. The default is NO.

See also:	− setLocksObjects:

qualifier

− (EOQualifier *)qualifier

Returns the EOQualifier the indicates which records or objects to fetch.

See also:	− setQualifier:

refreshesRefetchedObjects

− (BOOL)refreshesRefetchedObjects

Returns YES if existing objects are overwritten with fetched values when they’ve have been updated or changed. Returns NO if existing objects aren’t touched when their data is refetched (the fetched data is simply discarded). The default is NO.

See also:	− setRefreshesRefetchedObjects:

setEntityName:

− (void)setEntityName:(NSString *)entityName

Sets the name of the root entity to be fetched to entityName.

See also:	− isDeep, − entityName

setHints:

− (void)setHints:(NSDictionary *)hints

Sets the receiver’s hints to hints. Other objects can use these to alter or optimize fetch operations. See the description of the objectsWithFetchSpecification:editingContext: method in the EODatabaseContext class specification for an example.

See also:	− hints

setIsDeep:

− (void)setIsDeep:(BOOL)flag

Controls whether a fetch should include sub-entities of the receiver’s entity. If flag is YES, sub-entities are also fetched; if flag is NO, they aren’t. EOFetchSpecifications are deep by default.

For example, if you have a Person entity/class/table with two sub-entities and subclasses, Employee and Customer, fetching Persons deeply also fetches all Employees and Customers matching the qualifier, while fetching Persons shallowly fetches only Persons matching the qualifier.

See also:	− isDeep

setLocksObjects:

− (void)setLocksObjects:(BOOL)flag

Controls whether a fetch should result in the selected objects being locked in the data repository. If flag is YES it should, if NO it shouldn’t. The default is NO.

See also:	− locksObjects

setQualifier:

− (void)setQualifier:(EOQualifier *)qualifier

Sets the receiver’s qualifier to qualifier.

See also:	− qualifier

setRefreshesRefetchedObjects:

− (void)setRefreshesRefetchedObjects:(BOOL)flag

Controls whether existing objects are overwritten with fetched values when they’ve have been updated or changed. If flag is YES, they are; if flag is NO, they aren’t (the fetched data is simply discarded). The default is NO.

− refreshesRefetchedObjects

setSortOrderings:

− (void)setSortOrderings:(NSArray *)sortOrderings

Sets the receiver’s array of EOSortOrderings to sortOrderings. When a fetch is performed with the receiver, the results are sorted by applying each EOSortOrdering in the array.

See also:	− sortedArrayUsingKeyOrderArray: (NSArray Additions), − sortOrderings

setUsesDistinct:

− (void)setUsesDistinct:(BOOL)flag

Controls whether duplicate objects or records are removed after fetching. If flag is YES they’re removed; if flag is NO they aren’t. EOFetchSpecifications by default don’t use distinct.

See also:	− usesDistinct

sortOrderings

− (NSArray *)sortOrderings

Returns the receiver’s array of EOSortOrderings. When a fetch is performed with the receiver, the results are sorted by applying each EOSortOrdering in the array.

See also:	− sortedArrayUsingKeyOrderArray: (NSArray Additions), − setSortOrderings:

usesDistinct

− (BOOL)usesDistinct

Returns YES if duplicate objects or records are removed after fetching, NO if they aren’t. EOFetchSpecifications by default don’t use distinct.

See also:	− setUsesDistinct:


EOGlobalID

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	NSObject

Conforms To:	NSCopying

NSObject (NSObject)

Declared In:	EOControl/EOGlobalID.h

Class Description

An EOGlobalID is a compact, universal identifier for a persistent object, forming the basis for uniquing in Enterprise Objects Framework. An EOGlobalID uniquely identifies the same object or record both between EOEditingContexts in a single application, and in multiple applications (as in distributed systems). EOGlobalID is an abstract class, declaring only the methods needed for identification. A concrete subclass must define appropriate storage for identifying values (such as primary keys), as well as an initialization or creation method to build IDs. See the EOKeyGlobalID class specification in the Access layer for an example of a concrete ID class.

Temporary Identifiers

EOEditingContexts and other object stores support the insertion of new objects without established IDs, creating temporary IDs that get replaced with permanent ones as soon as the new objects are saved to their persistent stores. The temporary IDs are instances of the EOTemporaryGlobalID class.

When an EOObjectStore saves these newly inserted objects, it must replace the temporary IDs with persistent ones. When it does this, it must post an EOGlobalIDChangedNotification announcing the change so that observers can update their accounts of which objects are identified by which global IDs. The notification’s userInfo dictionary contains a mapping from the temporary IDs (the keys) to their permanent replacements (the values).

Adopted Protocols

NSCopying	− copyWithZone:

Method Types

Comparison and identification	− hash

− isEqual:

Distinguishing temporary IDs	− isTemporary

Instance Methods

hash

@protocol NSObject

− (unsigned int)hash

Returns an integer that can be used as a table address in a hash table structure. If two objects are equal (as determined by isEqual:), they must have the same hash value. For more information, see the descriptions of this method in the NSObject class and protocol specifications of the Foundation Framework.

isEqual:

@protocol NSObject

− (BOOL)isEqual:(id)anObject

Returns YES if the receiver and anObject share the same identifying values, NO if they don’t. For more information, see the descriptions of this method in the NSObject class and protocol specifications of the Foundation Framework.

isTemporary

− (BOOL)isTemporary

Returns NO. See the class description for more information.

Notifications

EOGlobalIDChangedNotification

Posted whenever EOTemporaryGlobalIDs are replaced by permanent EOGlobalIDs. The notification contains:

Notification Object	nil

Userinfo	A mapping from the temporary IDs (keys) to permanent IDs (values)


EOKeyComparisonQualifier

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	EOQualifier : NSObject

Conforms To:	EOQualifierEvaluation

EOQualifierSQLGeneration

Declared In:	EOControl/EOQualifier.h

Class Description

EOKeyComparisonQualifier is a subclass of EOQualifier that compares a named property of an object with a named value of another object. For example, to return all of the employees whose salaries are greater than those of their managers, you might use an expression such as “salary > manager.salary”, where “salary” is the left key and “manager.salary” is the right key. The “left key” is the property of the first object that’s being compared to a property in a second object; the property in the second object is the “right key”.

EOKeyComparisonQualifier adopts the EOQualifierEvaluation protocol, which defines the method evaluateWithObject: for in-memory evaluation. When an EOKeyComparisonQualifier object receives an evaluateWithObject: message, it evaluates the given object to determine if it satisfies the qualifier criteria.

In addition to performing in-memory filtering, EOKeyComparisonQualifier can be used to generate SQL. When it’s used for this purpose, the key should be a valid property name of the root entity for the qualifier (or a valid key path).

Adopted Protocols

EOQualifierEvaluation 	− evaluateWithObject:

EOQualifierSQLGeneration	− sqlStringForSQLExpression:

− schemaBasedQualifierWithRootEntity:

Method Types

Initializing an EOKeyComparisonQualifier

− initWithLeftKey:operatorSelector:rightKey:

Returning information about an EOKeyComparisonQualifier

− leftKey

− rightKey

− selector

Instance Methods

evaluateWithObject:

@protocol EOQualifierEvaluation

− (BOOL)evaluateWithObject:object

Returns YES if the object object satisfies the qualifier, NO otherwise. When an EOKeyComparisonQualifier object receives an evaluateWithObject: message, it evaluates object to determine if it meets the qualifier criteria. This method can raise one of several possible exceptions if an error occurs. If your application allows users to construct arbitrary qualifiers (such as through a user interface), you may want to put exception handlers around this method to properly respond to errors (for example, by displaying a panel saying that the user typed a poorly formed qualifier).

initWithLeftKey:operatorSelector:rightKey:

− initWithLeftKey:(NSString *)leftKey operatorSelector:(SEL)selector rightKey:(id)rightKey

Initializes the receiver to compare the properties named by leftKey and rightKey, using the operator selector selector.

EOQualifierOperatorEqual

EOQualifierOperatorNotEqual

EOQualifierOperatorLessThan

EOQualifierOperatorGreaterThan

EOQualifierOperatorLessThanOrEqualTo

EOQualifierOperatorGreaterThanOrEqualTo

EOQualifierOperatorContains

EOQualifierOperatorLike

Enterprise Objects Framework supports SQL generation for these selectors only.

For example, the following excerpt creates an EOKeyComparisonQualifier qual that has the left key ”lastName”, the operator selector EOQualifierOperatorEqual, and the right key ”member.lastName”. Once constructed, the qualifier qual is used to filter an in-memory array. The code excerpt returns an array of Guest objects whose lastName properties have the same value as the lastName property of the guest’s sponsoring member (this example is based on the Rentals sample database).

NSArray *guests;	    /* Assume this exists. */

EOQualifier *qual = [[EOKeyComparisonQualifier alloc]

initWithLeftKey:@"lastName"

operatorSelector:EOQualifierOperatorEqual

rightKey:@"member.lastName"];

return [guests filteredArrayUsingQualifier:qual];

leftKey

− (NSString *)leftKey

 Returns the receiver’s left key.

rightKey

− (NSString *)rightKey

 Returns the receiver’s right key.

selector

− (SEL)selector

Returns the receiver’s selector.


EOKeyValueQualifier

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	EOQualifier : NSObject

Conforms To:	EOQualifierEvaluation

EOQualifierSQLGeneration

Declared In:	EOControl/EOQualifier.h

Class Description

EOKeyValueQualifier is a subclass of EOQualifier that compares a named property of an object with a supplied value, for example, “salary > 1500". EOKeyValueQualifier adopts the EOQualifierEvaluation protocol, which defines the method evaluateWithObject: for in-memory evaluation. When an EOKeyValueQualifier object receives an evaluateWithObject: message, it evaluates the given object to determine if it satisfies the qualifier criteria.

In addition to performing in-memory filtering, EOKeyValueQualifier can be used to generate SQL. When it’s used for this purpose, the key should be a valid property name of the root entity for the qualifier (or a valid key path).

Adopted Protocols

EOQualifierEvaluation 	− evaluateWithObject:

EOQualifierSQLGeneration	− sqlStringForSQLExpression:

− schemaBasedQualifierWithRootEntity:

Method Types

Initializing an EOKeyValueQualifier	− initWithKey:operatorSelector:value:

Returning information about an EOKeyValueQualifier

− selector

− key

− value

Instance Methods

evaluateWithObject:

@protocol EOQualifierEvaluation

− (BOOL)evaluateWithObject:anObject

Returns YES if the object anObject satisfies the qualifier, NO otherwise. When an EOKeyValueQualifier object receives the evaluateWithObject: message, it evaluates object to determine if it meets the qualifier criteria. This method can raise one of several possible exceptions if an error occurs. If your application allows users to construct arbitrary qualifiers (such as through a user interface), you may want to put exception handlers around this method to properly respond to errors (for example, by displaying a panel saying that the user typed a poorly formed qualifier).

initWithKey:operatorSelector:value:

− initWithKey:(NSString *)key operatorSelector:(SEL)selector value:(id)value

Initializes the receiver to compare values for key to value using the operator selector selector. The possible values for selector are as follows:

EOQualifierOperatorEqual

EOQualifierOperatorNotEqual

EOQualifierOperatorLessThan

EOQualifierOperatorGreaterThan

EOQualifierOperatorLessThanOrEqualTo

EOQualifierOperatorGreaterThanOrEqualTo

EOQualifierOperatorContains

EOQualifierOperatorLike

Enterprise Objects Framework supports SQL generation for these selectors only.

For example, the following excerpt creates an EOKeyValueQualifier qual that has the key ”name”, the operator selector EOQualifierOperatorEqual, and the value ”Smith”. Once constructed, the qualifier qual is used to filter an in-memory array.

NSArray *employees;	    /* Assume this exists. */

EOQualifier *qual = [[EOKeyValueQualifier alloc] initWithKey:@"name"

    operatorSelector:EOQualifierOperatorEqual

    value:@"Smith"];

return [employees filteredArrayUsingQualifier:qual];

key

− (NSString *)key

Returns the receiver’s key.

selector

− (SEL)selector

 Returns the receiver’s selector.

value

− (id)value

 Returns the receiver’s value.


EOMessageHandlers

(informal protocol)

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Category Of:	NSObject

Declared In:	EOControl/EOEditingContext.h

Category Description

This category declares a single method, which an EOEditingContext uses to report errors to its designated message handler. See the EOEditingContext and EODisplayGroup class specifications for more information.

Instance Methods

editingContext:presentErrorMessage:

− (void)editingContext:(EOEditingContext *)anEditingContext presentErrorMessage:(NSString *)message

Invoked by anEditingContext, this method should present message to the user in whatever way appropriate (whether by opening an attention panel or printing the message in a terminal window). This method is declared, but not implemented by NSObject.


EONotQualifier

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	EOQualifier : NSObject

Conforms To:	EOQualifierEvaluation

EOQualifierSQLGeneration

Declared In:	EOControl/EOQualifier.h

Class Description

EONotQualifier is a subclass of EOQualifier that contains a single qualifier. When an EONotQualifier object is evaluated, it returns the inverse of the result obtained by evaluating the qualifier it contains.

EONotQualifier adopts the EOQualifierEvaluation protocol, which defines the method evaluateWithObject: for in-memory evaluation. When an EONotQualifier object receives an evaluateWithObject: message, it evaluates the given object to determine if it satisfies the qualifier criteria.

Adopted Protocols

EOQualifierEvaluation 	− evaluateWithObject:

EOQualifierSQLGeneration	− sqlStringForSQLExpression:

− schemaBasedQualifierWithRootEntity:

Method Types

Initialize an EONotQualifier	− initWithQualifier:

Return the EONotQualifier’s qualifier

− qualifier

Instance Methods

evaluateWithObject:

@protocol EOQualifierEvaluation

− (BOOL)evaluateWithObject:anObject

Returns YES if the object anObject satisfies the EONotQualifier, NO otherwise. This method can raise one of several possible exceptions if an error occurs. If your application allows users to construct arbitrary qualifiers (such as through a user interface), you may want to put exception handlers around this method to properly respond to errors (for example, by displaying a panel saying that the user typed a poorly formed qualifier).

initWithQualifier:

− initWithQualifier:(EOQualifier *)aQualifier

Initializes the receiver with the EOQualifier aQualifier. For example, the following code excerpt constructs a qualifier, baseQual, and uses it to initialize an EONotQualifier, negQual. The EONotQualifier negQual is then used to filter an in-memory array. The code excerpt returns an array of Guest objects whose lastName properties do not have the same value as the lastName property of the guest’s sponsoring member (this example is based on the Rentals sample database). In other words, the EONotQualifier negQual inverts the effects of baseQual.

NSArray *guests;	     /* Assume this exists. */

EOQualifier *baseQual, *negQual;

baseQual = [EOQualifier qualifierWithQualifierFormat:@"lastName =

 	member.lastName"];

negQual = [[EONotQualifier alloc] initWithQualifier:baseQual];

return [guests filteredArrayUsingQualifier:negQual];

qualifier

− (EOQualifier *)qualifier

 Returns the receiver’s qualifier.


EONull

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	NSObject

Conforms To:	NSCoding

NSCopying

NSObject (NSObject)

Declared In:	EOControl/EONull.h

Class Description

The EONull class defines a unique object used to represent null values in collection objects (which don’t allow nil values). For example, NSDictionaries fetched by an EOAdaptorChannel contain the EONull instance for such values. EONull is automatically translated to nil in enterprise objects, however, so most applications should rarely need to account for this class. See the NSObject Additions class specification for details on where this translation is performed.

EONull has exactly one instance, returned by the null class method. This object isn’t reference-counted, can’t be copied (copyWithZone: returns self), and is never deallocated. You can thus safely cache this instance and use pointer comparison to test for the presence of a null value:

static id NULL_VALUE;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification

{

    /* ... */

    NULL_VALUE = [EONull null];

    return;

}

if (value == NULL_VALUE) {

    /* ... */

}

Adopted Protocols

NSCoding	− encodeWithCoder:

− initWithCoder:

NSCopying	− copyWithZone:

Class Methods

null

+ (EONull *)null

Returns the unique instance of EONull.


EOObjectStore

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	NSObject

Conforms To:	NSObject (NSObject)

Declared In:	EOControl/EOObjectStore.h

Class Description

EOObjectStore is an abstract class defining the interface for an “intelligent” repository of objects, whether one based on external data or one that manages objects entirely in memory. An EOObjectStore is responsible for constructing and registering objects, servicing object faults, and saving changes made to objects. EOEditingContext is the principal subclass used for managing objects in memory—in fact, the primary purpose of the EOObjectStore interface is to service EOEditingContexts, not to define a completely general interface. The access layer’s EODatabaseContext class, a subclass of EOObjectStore, provides objects from relational databases. EODatabaseContexts, and other EOObjectStores based on external data, are often shared by several EOEditingContexts.

An EOObjectStore identifies its objects in two ways: by id for identification within a specific EOEditingContext, and by EOGlobalID for universal identification of the same record among multiple stores. EOObjectStores perform uniquing of their objects based on EOGlobalIDs, and use the IDs to coordinate changes among separate EOObjectStores—both within and, potentially, across applications—and between nested stores (as illustrated in the EOEditingContext class specification).

For external repositories, an EOObjectStore may delay actually fetching an object’s data, instead creating an EOFault as a placeholder. When an EOFault is accessed (sent a message), it triggers its EOObjectStore to fetch its data and transform it into an instance of the appropriate object class. This preserves both the object’s id and its EOGlobalID, while saving the cost of fetching data that may not be used. EOFaults are typically created for the destinations of relationships for objects that are explicitly fetched. See the EOFault and EOFaultHandler class specifications for more information.

Subclasses of EOObjectStore

As noted above, EOEditingContext is the principal subclass of EOObjectStore, used for managing objects in memory. For stores based on external data, there are several subclasses. EOCooperatingObjectStore defines stores that work together to manage data from several distinct sources (such as different databases). EODatabaseContext is actually a subclass of this class. A group of EOCooperatingObjectStores is managed by another subclass of EOObjectStore, called EOObjectStoreCoordinator. If you’re defining a subclass of EOObjectStore, it’s probably one based on an external data repository, and it should therefore inherit from EOCooperatingObjectStore so as to work well with an EOObjectStoreCoordinator—though this isn’t required.

A subclass of EOObjectStore must implement all of its methods. The default method implementations raise exceptions.

Method Types

Initializing objects	− initializeObject:withGlobalID:

Getting objects	− objectsWithFetchSpecification:editingContext:

− objectsForSourceGlobalID:relationshipName:editingContext:

Getting faults	− faultForGlobalID:editingContext:

− arrayFaultWithSourceGlobalID:relationshipName:editingContext:

− refaultObject:withGlobalID:editingContext:

Locking objects	− lockObjectWithGlobalID:editingContext:

− isObjectLockedWithGlobalID:editingContext:

Saving changes to objects	− saveChangesInEditingContext:

Invalidating objects	− invalidateAllObjects

− invalidateObjectsWithGlobalIDs:

Instance Methods

arrayFaultWithSourceGlobalID:relationshipName:editingContext:

− (NSArray *)arrayFaultWithSourceGlobalID:(EOGlobalID *)globalID

relationshipName:(NSString *)relationshipName

editingContext:(EOEditingContext *)anEditingContext

Implemented by subclasses to return the destination objects for a to-many relationship, whether as real instances or as an EOFault. globalID identifies the source object for the relationship (which doesn’t necessarily exist in memory yet), and relationshipName is the name of the relationship. The object identified by globalID and the destination objects for the relationship all belong to anEditingContext.

If you implement this method to return an EOFault, you must define an EOFaultHandler subclass that stores globalID and relationshipName, using them to fetch the objects in a later objectsForSourceGlobalID:relationshipName:editingContext: message and that turns the EOFault into an NSArray containing those objects. See the EOFaultHandler and EOFault class specifications for more information on faults.

See the EOEditingContext and EODatabaseContext class specifications for more information on how this method works in concrete subclasses.

See also:	− faultForGlobalID:editingContext:

faultForGlobalID:editingContext:

− (id)faultForGlobalID:(EOGlobalID *)globalID editingContext:(EOEditingContext *)anEditingContext

If the receiver is anEditingContext and the object associated with globalID is already registered in anEditingContext, returns that object. Otherwise creates a to-one fault, registers it in anEditingContext, and returns the fault. This method is always directed first at anEditingContext, which forwards the message to its parent object store if needed to create a fault.

If you implement this method to return an EOFault, you must define an EOFaultHandler subclass that stores globalID, uses it to fetch the object and turn the EOFault into that object, and initialize the object with EOObjectStore’s initializeObject:withGlobalID:. See the EOFaultHandler and EOFault class specifications for more information on faults.

See the EOEditingContext and EODatabaseContext class specifications for more information on how this method works in concrete subclasses.

See also:	− arrayFaultWithSourceGlobalID:relationshipName:editingContext:, − recordObject:globalID: (EOEditingContext)

initializeObject:withGlobalID:

− (void)initializeObject:(id)anObject

withGlobalID:(EOGlobalID *)globalID

editingContext:(EOEditingContext *)anEditingContext

Implemented by subclasses to set anObject’s properties, as obtained for globalID. This method is typically invoked after anObject has been creating using EOClassDescription’s createInstanceWithEditingContext:globalID:zone: and NSObject’s initWithEditingContext:classDescription:globalID:, and after a fault has been fired.

See also:	− initWithEditingContext:classDescription:globalID: (NSObject Additions), − awakeFromInsertionInEditingContext: (NSObject Additions), − awakeFromFetchInEditingContext: (NSObject Additions)

invalidateAllObjects

− (void)invalidateAllObjects

Discards the values of all objects held by the receiver and turns them into EOFaults. This causes all locks to be dropped and any transaction to be rolled back. The next time any object is accessed, its data is fetched anew. Any child object stores are also notified that the objects are no longer valid. See the EOEditingContext class specification for more information on how this method works in concrete subclasses.

This method should also post an EOInvalidatedAllObjectsInStoreNotification.

See also:	− invalidateObjectsWithGlobalIDs:, − refaultObject:withGlobalID:editingContext:

invalidateObjectsWithGlobalIDs:

− (void)invalidateObjectsWithGlobalIDs:(NSArray *)globalIDs

Signals that the objects identified by the EOGlobalIDs in globalIDs should no longer be considered valid and that they should be turned into EOFaults. This causes data for each object to be refetched the next time it’s accessed. Any child object stores are also notified that the objects are no longer valid.

See also:	− invalidateAllObjects, − refaultObject:withGlobalID:editingContext:

isObjectLockedWithGlobalID:editingContext:

− (BOOL)isObjectLockedWithGlobalID:(EOGlobalID *)globalID editingContext:(EOEditingContext *)anEditingContext

Returns YES if the object identified by globalID is locked, NO if it isn’t. See the EODatabaseContext class specification for more information on how this method works in concrete subclasses.

lockObjectWithGlobalID:editingContext:

− (void)lockObjectWithGlobalID:(EOGlobalID *)globalID editingContext:(EOEditingContext *)anEditingContext

Locks the object identified by globalID. See the EODatabaseContext class specification for more information on how this method works in concrete subclasses.

objectsForSourceGlobalID:relationshipName:editingContext:

− (NSArray *)objectsForSourceGlobalID:(EOGlobalID *)globalID

relationshipName:(NSString *)relationshipName

editingContext:(EOEditingContext *)anEditingContext

Returns the destination objects for a to-many relationship. This method is used by an array fault previously constructed using arrayFaultWithSourceGlobalID:relationshipName:editingContext:. globalID identifies the source object for the relationship (which doesn’t necessarily exist in memory yet), and relationshipName is the name of the relationship. The object identified by globalID and the destination objects for the relationship all belong to anEditingContext.

See the EOEditingContext and EODatabaseContext class specifications for more information on how this method works in concrete subclasses.

objectsWithFetchSpecification:editingContext:

− (NSArray *)objectsWithFetchSpecification:(EOFetchSpecification *)aFetchSpecification editingContext:(EOEditingContext *)anEditingContext

Fetches objects from an external store according to the criteria specified by fetchSpecification and returns them in an NSArray for inclusion in anEditingContext. If one of these objects is already present in memory, this method doesn’t overwrite its values with the new values from the database. Raises an exception if an error occurs.

See the EOEditingContext and EODatabaseContext class specifications for more information on how this method works in concrete subclasses.

refaultObject:withGlobalID:editingContext:

− (void)refaultObject:(id)anObject

withGlobalID:(EOGlobalID *)globalID

editingContext:(EOEditingContext *)anEditingContext

Turns anObject into an EOFault, identified by globalID in anEditingContext. This method should be used with caution since refaulting an object doesn’t remove the object snapshot from the undo stack. Objects that have been inserted but not saved, or that have been deleted, shouldn’t be refaulted.

saveChangesInEditingContext:

− (void)saveChangesInEditingContext:(EOEditingContext *)anEditingContext

Saves any changes in anEditingContext to the receiver’s repository. Sends insertedObjects, deletedObjects, and updatedObjects messages to anEditingContext and applies the changes to the receiver’s data repository as appropriate. For example, EODatabaseContext implements this method to send operations to an EOAdaptor for making the changes in a database.

Notifications

EOInvalidatedAllObjectsInStoreNotification

Posted whenever an EOObjectStore receives an invalidateAllObjects message. The notification contains:

Notification Object	The EOObjectStore that received the invalidateAllObjects message.

Userinfo	None

EOObjectsChangedInStoreNotification

Posted whenever an EOObjectStore observes changes to its objects. The notification contains:

Notification Object	The EOObjectStore that observed the change.

Userinfo

Key	Value

updated	An NSArray of EOGlobalIDs for objects whose properties have

changed. A receiving EOEditingContext typically responds by

refaulting its corresponding objects.

inserted	An NSArray of EOGlobalIDs for objects that have been inserted

into the EOObjectStore.

deleted	An NSArray of EOGlobalIDs for objects that have been deleted

from the EOObjectStore.

invalidated	An NSArray of EOGlobalIDs for objects that have been turned

into EOFaults.


EOObjectStoreCoordinator

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	EOObjectStore : NSObject

Conforms To:	NSObject (NSObject)

Declared In:	EOControl/EOObjectStoreCoordinator.h

Class Description

EOObjectStoreCoordinator provides the abstraction of a single object store by directing one or more EOCooperatingObjectStores in managing objects from distinct data respositories.

EOObjectStore Methods

EOObjectStoreCoordinator overrides the following EOObjectStore methods:

objectsWithFetchSpecification:editingContext:

objectsForSourceGlobalID:relationshipName:editingContext:

propertiesForObjectWithGlobalID:editingContext:

faultForGlobalID:editingContext:

arrayFaultWithSourceGlobalID:relationshipName:editingContext:

refaultObject:withGlobalID:editingContext:

saveChangesInEditingContext:

invalidateAllObjects

invalidateObjectWithGlobalID:

With the exception of saveChangesInEditingContext:, EOObjectStoreCoordinator’s implementation of these methods simply forwards the message to an EOCooperatingObjectStore or stores. The message invalidateAllObjects is forwarded to all EOCooperatingObjectStores. The rest of the messages are forwarded to the appropriate EOCooperatingObjectStore, based on which store responds YES to the messages ownsGlobalID:, ownsObject:, and handlesFetchSpecification: (which message is used to determine EOCooperatingObjectStore responsibility depends on the context). The EOObjectStore methods listed above aren’t documented in this class specification (except for saveChangesInEditingContext:)—for descriptions of them, see the EOObjectStore and EODatabaseContext class specifications

For the method saveChangesInEditingContext:, the EOObjectStoreCoordinator guides its EOCooperatingObjectStores through a multi-pass save protocol in which each EOCooperatingObjectStore saves its own changes and forwards remaining changes to other EOCooperatingObjectStores. For example, if in its recordChangesInEditingContext: method one EOCooperatingObjectStore notices the removal of an object from an “owning” relationship but that object belongs to another EOCooperatingObjectStore, it informs the other store by sending the EOObjectStoreCoordinator a forwardUpdateForObject:changes: message. For a more details, see the method description for saveChangesInEditingContext:.

Note:	Although it manages objects from multiple repositories, EOObjectStoreCoordinator doesn’t absolutely guarantee consistent updates when saving changes across object stores. If your application requires guaranteed distributed transactions, you can either provide your own solution by creating a subclass of EOObjectStoreCoordinator that integrates with a TP monitor, use a database server with built-in distributed transaction support, or design your application to write to only one object store per save operation (though it may read from multiple object stores). For more discussion of this subject, see the method description for saveChangesInEditingContext:.

Method Types

Initializing instances	− init

Setting the default coordinator	+ setDefaultCoordinator:

+ defaultCoordinator

Managing EOCooperatingObjectStores

− addCooperatingObjectStore:

− removeCooperatingObjectStore:

− cooperatingObjectStores

Saving changes	− saveChangesInEditingContext:

Communication between EOCooperatingObjectStores

− forwardUpdateForObject:changes:

− valuesForKeys:object:

Returning EOCooperatingObjectStores

− objectStoreForGlobalID:

− objectStoreForFetchSpecification:

− objectStoreForObject:

Getting the userInfo dictionary	− userInfo

− setUserInfo:

Class Methods

defaultCoordinator

+ (id)defaultCoordinator

Returns a shared instance of EOObjectStoreCoordinator.

setDefaultCoordinator:

+ (void)setDefaultCoordinator:(EOObjectStoreCoordinator *)coordinator

Sets a shared instance EOObjectStoreCoordinator.

Instance Methods

addCooperatingObjectStore:

− (void)addCooperatingObjectStore:(EOCooperatingObjectStore *)store

Adds store to the list of EOCooperatingObjectStores that need to be queried and notified about changes to enterprise objects. Posts the notification EOCooperatingStoreWasAdded.

See also:	 − removeCooperatingObjectStore:, − cooperatingObjectStores

cooperatingObjectStores

− (NSArray *)cooperatingObjectStores

Returns the receiver’s EOCooperatingObjectStores.

See also:	 − addCooperatingObjectStore:, − removeCooperatingObjectStore:

forwardUpdateForObject:changes:

− (void)forwardUpdateForObject:(id)object changes:(NSDictionary *)changes

Tells the receiver to forward a message from an EOCooperatingObjectStore to another store informing it that changes need to be made to object. For example, inserting an object in a relationship property of one EOCooperatingObjectStore might require changing a foreign key property in an object owned by another EOCooperatingObjectStore.

This method first locates the EOCooperatingObjectStore that’s responsible for applying the changes, and then it sends the store the message recordUpdateForObject:changes:.

See also:	− recordUpdateForObject:changes: (EOCooperatingObjectStore)

init

− init

Initializes a newly allocated EOObjectStoreCoordinator and returns self. This is the designated initializer for the EOObjectStoreCoordinator class.

objectStoreForFetchSpecification:

− (EOCooperatingObjectStore *)objectStoreForFetchSpecification:

(EOFetchSpecification *)fetchSpecification

Returns the EOCooperatingObjectStore responsible for fetching objects with fetchSpecification. Returns nil if no EOCooperatingObjectStore can be found that responds YES to handlesFetchSpecification:.

See also:	 − objectStoreForGlobalID:, − objectStoreForObject:

objectStoreForGlobalID:

− (EOCooperatingObjectStore *)objectStoreForGlobalID:(EOGlobalID *)globalID

Returns the EOCooperatingObjectStore for the object identified by globalID. Returns nil if no EOCooperatingObjectStore can be found that responds YES to ownsGlobalID:.

See also:	 − objectStoreForFetchSpecification:, − objectStoreForObject:

objectStoreForObject:

− (EOCooperatingObjectStore *)objectStoreForObject:(id)object

Returns the EOCooperatingObjectStore that owns object. Returns nil if no EOCooperatingObjectStore can be found that responds YES to ownsObject:.

See also:	 − objectStoreForFetchSpecification:, − objectStoreForGlobalID:

removeCooperatingObjectStore:

− (void)removeCooperatingObjectStore:(EOCooperatingObjectStore *)store

Removes store from the list of EOCooperatingObjectStores that need to be queried and notified about changes to enterprise objects. Posts the notification EOCooperatingStoreWasRemoved.

See also:	 − addCooperatingObjectStore:, − cooperatingObjectStores

saveChangesInEditingContext:

− (void)saveChangesInEditingContext:(EOEditingContext *)anEditingContext

Overrides the EOObjectStore method saveChangesInEditingContext: to save the changes made in anEditingContext. This message is sent by an EOEditingContext to an EOObjectStoreCoordinator to commit changes. When an EOObjectStoreCoordinator receives this message, it guides its EOCooperatingObjectStores through a multi-pass save protocol in which each EOCooperatingObjectStore saves its own changes and forwards remaining changes to other EOCooperatingObjectStores. When this method is invoked, the following sequence of events occurs:

1.	The receiver sends each of its EOCooperatingObjectStores the message prepareForSaveWithCoordinator:editingContext:, which informs them that a multi-pass save operation is beginning. When the EOCooperatingObjectStore is an EODatabaseContext, it takes this opportunity to generate primary keys for any new objects in the EOEditingContext.

2.	The receiver sends each of its EOCooperatingObjectStores the message recordChangesInEditingContext, which prompts them to examine the changed objects in the EOEditingContext, record any operations that need to be performed, and notify the receiver of any changes that need to be forwarded to other EOCooperatingObjectStores. For example, if in its recordChangesInEditingContext: method one EOCooperatingObjectStore notices the removal of an object from an “owning” relationship but that object belongs to another EOCooperatingObjectStore, it informs the other store by sending the EOObjectStoreCoordinator a forwardUpdateForObject:changes: message.

3.	The receiver sends each of its EOCooperatingObjectStores the message performChanges. This tells the stores to transmit their changes to their underlying databases. When the EOCooperatingObjectStore is an EODatabaseContext, it responds to this message by taking the EODatabaseOperations that were constructed in the previous step, constructing EOAdaptorOperations from them, and giving the EOAdaptorOperations to an available EOAdaptorChannel for execution.

4.	If performChanges fails for any of the EOCooperatingObjectStores, all stores are sent the message rollbackChanges.

5.	If performChanges succeeds for all EOCooperatingObjectStores, the receiver sends them the message commitChanges, which has the effect of telling the adaptor to commit the changes.

6.	If commitChanges fails for a particular EOCooperatingObjectStore, that EOCooperatingObjectStore and all subsequent ones are sent the message rollbackChanges. However, the EOCooperatingObjectStores that have already committed their changes do not roll back. In other words, the EOObjectStoreCoordinator doesn't perform the two-phase commit protocol necessary to guarantee consistent distributed update.

This method raises an exception if an error occurs.

setUserInfo:

− (void)setUserInfo:(NSDictionary *)dictionary

Sets the dictionary of auxiliary data, which your application can use for whatever it needs.

See also:	− userInfo

userInfo

− (NSDictionary *)userInfo

Returns a dictionary of user data. Your application can use this to store any auxiliary information it needs.

See also:	− setUserInfo:

valuesForKeys:object:

− (NSDictionary *)valuesForKeys:(NSArray *)keys object:(id)object

Communicates with the appropriate EOCooperatingObjectStore to get the values identified by keys for object, so that it can then forward them on to another EOCooperatingObjectStore. EOCooperatingObjectStores can hold values for an object that augment the properties in the object. For instance, an EODatabaseContext stores foreign key information for the objects it owns. These foreign keys may well not be defined as properties of the object. Other EODatabaseContexts can find out the object’s foreign keys by sending the EODatabaseContext that owns the object a valuesForKeys:object: message (through the EOObjectStoreCoordinator).

Notifications

The following notifications are declared and posted by EOObjectStoreCoordinator.

EOCooperatingObjectStoreWasAdded

Notification Object	The EOObjectStoreCoordinator.

userInfo Dictionary	None.

When an EOObjectStoreCoordinator receives an addCooperatingObjectStore: message and adds an EOCooperatingObjectStore to its list, it posts EOCooperatingStoreWasAdded to notify observers.

EOCooperatingObjectStoreWasRemoved

Notification Object	The EOObjectStoreCoordinator.

userInfo Dictionary	None.

When an EOObjectStoreCoordinator receives a removeCooperatingObjectStore: message and removes an EOCooperatingObjectStore from its list, it posts EOCooperatingStoreWasRemoved to notify observers.


EOObserverCenter

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	NSObject

Conforms To:	NSObject (NSObject)

Declared In:	EOControl/EOObserver.h

Class Description

EOObserverCenter and related classes form an efficient, specialized mechanism for notification of changes to objects. Observable objects invoke the willChange method before altering their state, which causes all registered observers to receive an objectWillChange: message. The entire observation mechanism is defined by four classes and a protocol: EOObserverCenter, EODelayedObserverQueue, EODelayedObserver, EOObserverProxy, and EOObserving. EOObserverCenter is the central manager of change notification. It records all observers and the objects they observe, and distributes the objectWillChange: message defined by the EOObserving protocol. The other three classes add to the basic observation mechanism. EODelayedObserverQueue alters the basic, synchronous change notification mechanism by offering different priority levels, which allows observers to specify the order in which they’re notified of changes. EODelayedObserver is an abstract superclass for objects that observe other objects (such as the Interface layer’s EOAssociation classes). Finally, EOObserverProxy is a subclass of EODelayedObserver that forwards change messages to a target object, allowing objects that don’t inherit from EODelayedObserver to take advantage of this mechanism.

The major observer in Enterprise Objects Framework is EOEditingContext, which implements its objectWillChange: method to record a snapshot for the object about to change, register undo operations in an EOUndoManager, and record the changes needed to update objects in its EOObjectStore. Because some of these actions—such as examining the object’s new state—can only be performed after the object has changed, an EOEditingContext sets up a delayed message to itself, which it gets at the end of the run loop. Observers that only need to examine an object after it has changed can use the delayed observer mechanism, described in the EODelayedObserver and EODelayedObserverQueue class specifications.

Registering an Observer

Objects that directly observe others must adopt the EOObserving protocol, which consists of the single method objectWillChange:. To register an object as an observer, invoke EOObserverCenter’s addObserver:forObject: with the observer and the object to be observed. Once this is done, any time the object invokes its willChange method, the observer is sent an objectWillChange: message informing it of the pending change. You can also register an observer to be notified when any object changes using addOmniscientObserver:. This can be useful in certain situations, but as it’s very costly to deal out frequent change notifications, you should use omniscient observers sparingly. To unregister either kind of observer, simply use the corresponding remove... method.

Change Notification

Objects that are about to change invoke willChange, a method that the Framework adds to NSObject. This method invokes EOObserverCenter’s notifyObserversObjectWillChange:, which sends an objectWillChange: message to all observers registered for the object that’s changing, as well as to any omniscient observers. notifyObserversObjectWillChange: optimizes the process by suppressing redundant objectWillChange: messages when the same object invokes willChange several times in a row (as often happens when multiple properties are changed). Change notification is immediate, and takes place before the object’s state changes. If you need to compare the object’s state before and after the change, you must arrange to examine the new state at the end of the run loop.

You can suppress change notification when necessary, using the suppressObserverNotification and enableObserverNotification methods. While notification is suppressed, neither regular nor omniscient observers are informed of changes. These methods nest, so you can invoke suppressObserverNotification multiple times, and notification isn’t reenabled until a matching number of enableObserverNotification message have been sent.

Method Types

Registering and unregistering observers

+ addObserver:forObject:

+ removeObserver:forObject:

+ addOmniscientObserver:

+ removeOmniscientObserver:

Notifying observers of change	+ notifyObserversObjectWillChange:

Getting observers	+ observersForObject:

+ observerForObject:ofClass:

Suppressing change notification	+ suppressObserverNotification

+ enableObserverNotification

+ observerNotificationSuppressCount

Class Methods

addObserver:forObject:

+ (void)addObserver:(id <EOObserving>)anObserver forObject:(id)anObject

Records anObserver to be notified with an objectWillChange: message when anObject changes.

See also:	+ notifyObserversObjectWillChange:, + removeObserver:forObject:, + observersForObject:

addOmniscientObserver:

+ (void)addOmniscientObserver:(id <EOObserving>)anObserver

Records anObserver to be notified with an objectWillChange: message when any object changes. This can cause significant performance degradation, and so should be used with care.

See also:	+ notifyObserversObjectWillChange:, + addObserver:forObject:, + removeOmniscientObserver:

enableObserverNotification

+ (void)enableObserverNotification

Counters a prior suppressObserverNotification message. When no such messages remain in effect, the notifyObserversObjectWillChange: method is reenabled. Raises an NSInternalInconsistencyException if not paired with a prior suppressObserverNotification message.

See also:	+ observerNotificationSuppressCount

notifyObserversObjectWillChange:

+ (void)notifyObserversObjectWillChange:(id)anObject

Unless change notification is suppressed, sends an objectWillChange: to all observers registered for anObject with that object as the argument, and sends that message to all omniscient observers as well. If invoked several times in a row with the same object, only the first invocation has any effect, since the following change notifications are redundant.

See also:	+ suppressObserverNotification, + addObserver:forObject:, + addOmniscientObserver:

observerForObject:ofClass:

+ (id)observerForObject:(id)anObject ofClass:(Class)aClass

Returns an observer for anObject that’s a kind of aClass. If more than one observer of anObject is a kind of aClass, the specific observer returned is undetermined. You can use observersForObject: instead to get all observers and examine their class membership.

observerNotificationSuppressCount

+ (unsigned int)observerNotificationSuppressCount

Returns the number of suppressObserverNotification messages in effect.

See also:	+ enableObserverNotification

observersForObject:

+ (NSArray *)observersForObject:(id)anObject

Returns all observers of anObject.

See also:	+ observerForObject:ofClass:

removeObserver:forObject:

+ (void)removeObserver:(id <EOObserving>)anObserver forObject:(id)anObject

Removes anObserver as an observer of anObject.

See also:	+ notifyObserversObjectWillChange:, + addObserver:forObject:, + observersForObject:

removeOmniscientObserver:

+ (void)removeOmniscientObserver:(id <EOObserving>)anObserver

Unregisters anObserver as an observer of all objects.

See also:	+ notifyObserversObjectWillChange:, + removeObserver:forObject:, + addOmniscientObserver:

suppressObserverNotification

+ (void)suppressObserverNotification

Disables the notifyObserversObjectWillChange: method, so that no change notifications are sent. This method can be invoked multiple times; enableObserverNotification must then be invoked an equal number of times to reenable change notification.

See also:	+ observerNotificationSuppressCount


EOObserverProxy

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	EODelayedObserver : NSObject

Conforms To:	EOObserving (EODelayedObserver)

NSObject (NSObject)

Declared In:	EOControl/EOObserver.h

Class Description

EOObserverProxy provides a means for objects that can’t inherit from EODelayedObserver to handle subjectChanged messages. An EOObserverProxy implements subjectChanged to send an action message to its target object, allowing the target to act as though it had received subjectChanged directly from an EODelayedObserverQueue. See the EOObserverCenter and EODelayedObserverQueue class specifications for more information.

Instance Methods

initWithTarget:action:priority:

− (id)initWithTarget:(id)anObject

action:(SEL)anAction

priority:(EOObserverPriority)priority

Initializes a new EOObserverProxy to send anAction to anObject upon receiving a subjectChanged message. anAction should be a selector for a typical action method, taking one id argument and returning void. priority indicates when the receiver is sent this message from EODelayedObserverQueue’s notifyObserversUpToPriority: method. This is the designated initializer for the EOObserverProxy class. Returns self.


EOObserving

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Adopted By:	EODelayedObserver

EOEditingContext

Declared In:	EOControl/EOObserver.h

Protocol Description

The EOObserving protocol declares the objectWillChange: method, used by observers to receive notifications that an object has changed. This message is sent by EOObserverCenter to all observers registered using its addObserver:forObject: method. See the EOObserverCenter class specification for more information.

Instance Methods

objectWillChange:

− (void)objectWillChange:(id)anObject

Informs the receiver that anObject’s state is about to change. The receiver can record anObject’s state, mark or record it as changed, and examine it later (such as at the end of the run loop) to see how it’s changed.


EOOrQualifier

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	EOQualifier : NSObject

Conforms To:	EOQualifierEvaluation

EOQualifierSQLGeneration

Declared In:	EOControl/EOQualifier.h

Class Description

EOOrQualifier is a subclass of EOQualifier that contains multiple qualifiers. EOOrQualifier adopts the EOQualifierEvaluation protocol, which defines the method evaluateWithObject: for in-memory evaluation. When an EOOrQualifier object receives an evaluateWithObject: message, it evaluates each of its qualifiers until one of them returns YES. If one of its qualifiers returns YES, the EOOrQualifier object returns YES immediately. If all of its qualifiers return NO, the EOOrQualifier object returns NO.

Adopted Protocols

EOQualifierEvaluation 	− evaluateWithObject:

EOQualifierSQLGeneration	− sqlStringForSQLExpression:

− schemaBasedQualifierWithRootEntity:

Method Types

Initializing an EOOrQualifier	− initWithQualifierArray:

− initWithQualifiers:

Returning an EOOrQualifier’s qualifiers

− qualifiers

Instance Methods

evaluateWithObject:

@protocol EOQualifierEvaluation

− (BOOL)evaluateWithObject:(id)anObject

Returns YES if anObject satisfies the qualifier, NO otherwise. When an EOOrQualifier object receives an evaluateWithObject: message, it evaluates each of its qualifiers until one of them returns YES. If any of its qualifiers returns YES, the EOOrQualifier object returns YES immediately. If all of its qualifiers return NO, the EOOrQualifier object returns NO. This method can raise one of several possible exceptions if an error occurs. If your application allows users to construct arbitrary qualifiers (such as through a user interface), you may want to put exception handlers around this method to properly respond to errors (for example, by displaying a panel saying that the user typed a poorly formed qualifier).

initWithQualifierArray:

− initWithQualifierArray:(NSArray *)qualifiers

Initializes the receiver with the qualifiers qualifiers and returns self. This method is the designated initializer for EOOrQualifier.

initWithQualifiers:

− initWithQualifiers:(EOQualifier *)qualifiers,...

Initializes the receiver with the nil-terminated list of qualifiers qualifiers. Works by invoking initWithQualifierArray:. For example, the following code excerpt constructs three qualifiers, qual1, qual2, and qual3. It then uses these qualifiers to initialize an EOOrQualifier, orQual. orQual is then used to filter an in-memory array.

NSArray *guests;    /* Assume this exists. */

EOQualifier *qual1, *qual2, *qual3, *orQual;

qual1 = [EOQualifier qualifierWithQualifierFormat:@"lastName = 'Nunez'"];

qual2 = [EOQualifier qualifierWithQualifierFormat:@"lastName = 'Wren'"];

qual3 = [EOQualifier qualifierWithQualifierFormat:@"lastName = 'Wilson'"];

/* Initialize the EOOrQualifier orQual using a nil-terminated list of

 * qualifiers.

 */

orQual = [[EOOrQualifier alloc] initWithQualifiers:qual1, qual2, qual3, nil];

/* Use orQual to filter the array guests. */

return [guests filteredArrayUsingQualifier:orQual];

qualifiers

− (NSArray *)qualifiers

 Returns the receiver’s qualifiers.


EOQualifier

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	NSObject

Conforms To:	NSCopying

Declared In:	EOControl/EOQualifier.h

Class Description

EOQualifier is an abstract class for objects that hold information used to restrict selections on objects or database rows according to specified criteria. With the exception of EOSQLQualifier, qualifiers aren’t based on SQL and they don’t rely upon an EOModel. Thus, the same qualifier can be used both to perform in-memory searches and to fetch from the database.

The subclasses of EOQualifier are as follows:

EOKeyValueQualifier	Compares the named property of an object to a supplied value, for

example, “weight > 150”.

EOKeyComparisonQualifier	Compares the named property of one object with the named

property of another, for example “name = wife.name”.

EOAndQualifier           	Contains multiple qualifiers, which it conjoins. For example,

“name = ’Fred’ AND age < 20”.

EOOrQualifier	Contains multiple qualifiers, which it disjoins. For example,

“name = ’Fred’ OR name = ’Ethel’”.

EONotQualifier	Contains a single qualifier, which it negates. For example,

“NOT (name = ’Fred’)”.

EOSQLQualifier           	Contains unstructured text that can be transformed into a SQL

expression. EOSQLQualifier is provided for backward compatibility

with pre-2.0 Enterprise Objects Framework releases and to provide a

way to create SQL expressions with any arbitrary SQL. Because

EOSQLQualifiers can’t be evaluated against objects in memory,

 	you should use EOQualifier whenever possible and only use

 	EOSQLQualifier in cases that absolutely require it.

With the exception of EOSQLQualifier, all of the subclasses are essentially key-value based and implement the protocol EOQualifierEvaluation, which means that their objects can be evaluated in memory. The subclasses also implement the protocol EOQualifierSQLGeneration, which allows them to generate SQL. Note that all of the SQL generation functionality is contained in the access layer. For more information, see the specifications for EOQualifierEvaluation, EOQualifierSQLGeneration, and the individual subclasses.

Creating a Qualifier

As described above, there are several EOQualifier subclasses, each of which represents a different semantic. However, in most cases you simply create a qualifier using the EOQualifier class method qualifierWithQualifierFormat:, as follows:

EOQualifier *qual = [EOQualifier

qualifierWithQualifierFormat:@"lastName = 'Smith'"];

The qualifier or group of qualifiers that result from such a statement is based on the contents of the format string you provide. For example, giving the format string “lastName = ’Smith’" as an argument to qualifierWithQualifierFormat: returns an EOKeyValueQualifier object. But you don’t normally need to be concerned with this level of detail.

The format strings you use to create a qualifier can be compound logical expressions, such as “firstName = ’Fred’ AND age < 20”. When you create a qualifier, compound logical expressions are translated into a tree of EOQualifier nodes. Logical operators such as AND and OR become EOAndQualifiers and EOOrQualifiers, respectively. These qualifiers conjoin (AND) or disjoin (OR) a group of sub-qualifiers.

Note:	The qualifierWithQualifierFormat: method can’t be used to create an instance of EOSQLQualifier. This is because EOSQLQualifier uses a non-structured syntax to provide backward compatibility with pre-2.0 Enterprise Objects Framework releases. It also requires an entity. To create an instance of EOSQLQualifier, you’d use a statement such as the following:

myQual = [[EOSQLQualifier alloc] initWithEntity:myEntity format:myFormatString];

Constructing Format Strings

As described above, you typically create a qualifier from a format string by using qualifierWithQualifierFormat:. This method takes as an argument a format string somewhat like that used with the standard C printf() function. The format string can embed strings, numbers, and objects using the conversion specifications listed below. This allows qualifiers to be built dynamically. The following table lists the conversion specifications you can use in a format string and their corresponding data types.

Conversion Specification	Expected Value or Result

%s	A constant C string (const char *).

%d	An int.

%f	A float or double.

%@	An id argument—valid objects are EOAttribute, NSString, or anything

 	that responds to expressionValueForContext:. The behavior of this

conversion specification depends on its position. It can either be an object

whose description method returns a key (in other words, an NSString), or

a value such as an NSString, NSNumber, NSCalendarDate, and so on.

%%	Results in a literal % character.

Note:	If you use an unrecognized character in a conversion specification (for example, %x), an NSInvalidArgumentException is raised.

For example, suppose you have an Employee entity with the properties empID, firstName, lastName, salary, and department (representing a to-one relationship to the employee’s department), and a Department entity with properties deptID, and name. You could construct simple qualifier strings like the following:

lastName = ’Smith’

salary > 2500

department.name = ’Personnel’

The following examples build qualifiers similar to the qualifier strings described above, but take the specific values from an already-fetched enterprise object:

myQualifier = [EOQualifier qualifierWithQualifierFormat:@"%@ = %@",

@"lastName", [anEmployee lastName]];

myQualifier = [EOQualifier qualifierWithQualifierFormat:@"%@ > %f",

@"salary", [anEmployee salary]];

myQualifier = [EOQualifier qualifierWithQualifierFormat:@"%@ = %@",

 	@"department.name", [aDept name]];

The enterprise objects here implement convenience methods for directly accessing the given attributes: lastName and salary for Employee objects, and name for Department objects.

Note:	Unlike a string literal, the %@ conversion specification is never surrounded by single quotes:

// For a literal string value such as Smith, you use single quotes.

[EOQualifier qualifierWithQualifierFormat:@"lastName = 'Smith'"];

// For the conversion specification %@, you don’t use quotes

[EOQualifier qualifierWithQualifierFormat:@"lastName = %@", @"Jones"];

Typically format strings include only two data types: strings and numbers. Single-quoted or double-quoted strings are NSStrings, non-quoted numbers are NSNumber, and non-quoted strings are keys. You can get around this limitation by performing explicit casting, as described in the section “Using Different Data Types.”

The operators you can use in constructing qualifiers are  =, ==, !=, <, >, <=, >=, “contains,” and “like”. The like operator can be used with wildcards to perform pattern matching, as described in the following section.

Using Wildcards

When you use the like operator in a qualifier expression, you can use the * and ? wildcard characters to perform pattern matching, for example:

@"lastName like ’Jo*’"

matches Jones, Johnson, Jolsen, Josephs, and so on.

The ? character just matches a single character, for example:

@"lastName like ’Jone?’"

matches Jones.

The asterisk character (*) is only interpreted as a wildcard in expressions that use the like operator. For example, in the following statement, the character * is treated as a literal value, not as a wildcard:

@"lastName = ’Jo*’"	// The * character doesn’t act as a wildcard in this statement.

Using Selectors in Qualifier Expressions

The format strings you use to initialize a qualifier can include selectors. The parser recognizes a selector as an unquoted string followed by a colon, such as myMethod:. For example:

point1 isInside: area

firstName isAnagramOfString: "Computer"

Selectors in a qualifier are parsed and applied in memory; that is, they can’t be used in SQL generation.

Using Different Data Types

As stated in the section “Constructing Format Strings,” format strings normally include only two data types: strings and numbers. To get around this limitation, you can perform explicit casting.

For example, NSCalendarDate and NSDecimalNumber are two classes that are likely to be used in qualifiers. You can construct format strings that for objects of these classes as follows:

hireDate = (NSCalendarDate)"Sept 14, 1993"

salary = (NSDecimalNumber)"15000.02"

When you use this approach, qualifiers are constructed by looking up the class and invoking [[class alloc] initWithString:stringValue]. Therefore, this technique only works for classes that implement initWithString:.

Using EOQualifier’s Subclasses

You rarely need to explicitly create an instance of EOAndQualifier, EOOrQualifier, or EONotQualifier. However, you may want to create instances of EOKeyValueQualifier and EOKeyComparisionQualifier. The primary advantage of this is that it lets you exercise more control over how the qualifier is constructed, which is desirable in some cases.

The following code excerpt uses EOKeyValueQualifier to select all objects whose “isOut” key is equal to YES. Once constructed, the qualifier is used to filter an in-memory array.

// Create the qualifier

EOQualifier *qual = [[EOKeyValueQualifier alloc] initWithKey:@"isOut"

    operatorSelector:EOQualifierOperatorEqual

    value:[NSNumber numberWithBool:YES]];

// Filter an array and return it

return [[self allRentals] filteredArrayUsingQualifier:qual];

filteredArrayUsingQualifier: is a method that Enterprise Objects Framework adds to NSArray. It’s used for filtering in-memory arrays.

Creating Subclasses

EOQualifier offers extensibility across two dimensions: new classes can be added to extend qualifier semantics, and categories can be added to extend functionality (for example, to provide in-memory evaluation).

Subclasses used to evaluate objects in memory must implement the EOQualifierEvaluation protocol. Subclasses used to generate SQL queries must conform to the EOQualifierSQLGeneration protocol.

Adopted Protocols

 NSCopying

Method Types

Create a qualifier	+ qualifierWithQualifierFormat:

+ qualifierWithQualifierFormat:arguments:

Convert strings and operators	+ operatorSelectorForString:

+ stringForOperatorSelector:

Validate a qualifier’s keys	− validateKeysWithRootClassDescription:

Class Methods

operatorSelectorForString:

+ (SEL)operatorSelectorForString:(NSString *)aString

Returns an operator selector based on the string aString. This method is used in parsing a qualifier. For example, the following statement returns the selector isNotEqualTo:.

selector = [EOQualifier operatorSelectorForString:@"!="];

The possible values of string are  =, ==, !=, <, >, <=, >=, “like”, and “contains”.

You’d probably only use this method if you were writing your own qualifier parser.

See also:	+ stringForOperatorSelector:

qualifierWithQualifierFormat:

+ (EOQualifier *)qualifierWithQualifierFormat:(NSString *)qualifierFormat, ...

Parses the format string qualifierFormat, uses it to create an EOQualifier, and returns the EOQualifier. Based on the content of qualifierFormat, generates a tree of the basic qualifier types. For example, the format string “firstName = 'Joe' AND department = ’Facilities’" generates an EOAndQualifier that contains two “sub” EOKeyValueQualifiers. The following code excerpt shows a typical way to use the qualifierWithQualifierFormat: method. The excerpt constructs an EOFetchSpecification, which includes an entity name and a qualifier. It then applies the EOFetchSpecification to the EODisplayGroup’s data source and tells the EODisplayGroup to fetch.

EODisplayGroup *displayGroup;	     /* Assume this exists.*/

EOFetchSpecification *fetchSpec;

EODatabaseDataSource *dataSource;

dataSource = [displayGroup dataSource];

fetchSpec = [EOFetchSpecification

fetchSpecificationWithEntityName:@"Member"

qualifier:[EOQualifier qualifierWithQualifierFormat:

@"cardType = 'Visa' "]

sortOrderings:nil];

[dataSource setFetchSpecification:fetchSpec];

[displayGroup fetch];

qualifierWithQualifierFormat: performs no verification to ensure that keys referred to by the format string qualifierFormat exist. It raises an NSInvalidArgumentException if qualifierFormat contains any syntax errors.

qualifierWithQualifierFormat:arguments:

+ (EOQualifier *)qualifierWithQualifierFormat:(NSString *)qualifierFormat

arguments:(NSArray *)arguments

Parses the format string qualifierFormat and the specified arguments, uses them to create an EOQualifier, and returns the EOQualifier. This method is equivalent to qualifierWithQualifierFormat: except that format characters (for example, %@, %d, %f) in qualifierFormat cause the method to search in the arguments array for values rather than in a variable argument list.

stringForOperatorSelector:

+ (NSString *)stringForOperatorSelector:(SEL)aSelector

Returns an NSString representation of the selector aSelector. For example, the following statement returns the string “!=”:

operator = [EOQualifier stringForOperatorSelector:EOQualifierOperatorNotEqual];

The possible values for selector are as follows:

EOQualifierOperatorEqual

EOQualifierOperatorNotEqual

EOQualifierOperatorLessThan

EOQualifierOperatorGreaterThan

EOQualifierOperatorLessThanOrEqualTo

EOQualifierOperatorGreaterThanOrEqualTo

EOQualifierOperatorContains

EOQualifierOperatorLike

You’d probably only use this method if you were writing your own parser.

See also:	 + operatorSelectorForString:

Instance Methods

validateKeysWithRootClassDescription:

- (NSException *)validateKeysWithRootClassDescription:(EOClassDescription *)classDesc

Validates that a qualifier contains keys and key paths that belong to or originate from classDesc. This method returns an NSInternalInconsistencyException if an unknown key is found, otherwise it returns nil to indicate that the keys contained by the qualifier are valid.


EOQualifierEvaluation

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Adopted By:	EOKeyValueQualifier

EOComparisonQualifier

EOAndQualifier

EOOrQualifier

EONotQualifier

Protocol Description

The EOQualifierEvaluation protocol defines a method, evaluateWithObject:, which performs in-memory evaluation of qualifiers. All qualifier classes whose objects can be evaluated in memory must implement this protocol.

Instance Methods

evaluateWithObject:

− (BOOL)evaluateWithObject:object

Returns YES if the argument object satisfies the qualifier, NO otherwise. This method can raise one of several possible exceptions if an error occurs, depending on the implementation.


EOSortOrdering

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	NSObject

Conforms To:	NSCoding

NSObject (NSObject)

Declared In:	EOControl/EOSortOrdering.h

Class Description

An EOSortOrdering records the way that a group of objects should be sorted, using a property key and a method selector for comparing values of that property. EOSortOrderings are used both to generate SQL when fetching rows from a database server, and to sort objects in memory. Both the EOFetchSpecification class and the added NSArray sorting methods accept an array of EOSortOrderings, which are applied in series to perform sorts by more than one property.

Sorting with SQL

When an EOSortOrdering is used to fetch data from a relational database, it’s rendered into a SQL ORDER BY clause for a SELECT statement. The Framework predefines symbols for four comparison selectors, rendered into SQL as:

Defined Name	SQL Expression

EOCompareAscending	(key) asc

EOCompareDescending	(key) desc

EOCompareCaseInsensitiveAscending	upper(key) asc

EOCompareCaseInsensitiveDescending	upper(key) desc

This sort ordering:

NSArray *nameOrdering = [NSArray arrayWithObjects:

    [EOSortOrdering sortOrderingWithKey:@"lastName" selector:EOCompareAscending],

    [EOSortOrdering sortOrderingWithKey:@"firstName" selector:EOCompareAscending],

    nil];

results in this ORDER BY clause:

order by (lastName) asc, (firstName) asc

In-Memory Sorting

Enterprise Objects Framework adds a method each to NSArray and NSMutableArray for sorting objects in memory. NSArray’s sortedArrayUsingKeyOrderArray: returns a new NSArray sorted using an array of EOSortOrderings. Similarly, NSMutableArray’s sortUsingKeyOrderArray: sorts the receiver’s contents. This code fragment, for example, sorts an array of Employee objects by last name, then first name using the EOSortOrdering created above:

NSArray *sortedEmployees = [employees sortedArrayUsingKeyOrderArray:nameOrdering];

The predefined comparison selectors are:

Defined Name	Selector

EOCompareAscending	compareAscending:

EOCompareDescending	compareDescending:

EOCompareCaseInsensitiveAscending	compareCaseInsensitiveAscending:

EOCompareCaseInsensitiveDescending	compareCaseInsensitiveDescending:

The first two can be used with any value class; the second two with NSString objects only. The NSArray sorting methods extract property values using the key-value coding protocol and apply the selectors to the values. If you use custom value classes, you should be sure to implement the appropriate comparison methods to avoid exceptions when sorting objects.

Adopted Protocols

NSCoding	− encodeWithCoder:

− initWithCoder:

Method Types

Creating instances	+ sortOrderingWithKey:selector:

− initWithKey:selector:

Examining a sort ordering	− key

− selector

Class Methods

sortOrderingWithKey:selector:

+ (EOSortOrdering *)sortOrderingWithKey:(NSString *)key selector:(SEL)aSelector

Creates and returns an EOSortOrdering based on key and selector.

See also:	− initWithKey:selector:

Instance Methods

initWithKey:selector:

− (id)initWithKey:(NSString *)key selector:(SEL)aSelector

Initializes a newly allocated EOSortOrdering based on key and selector and returns self. This is the designated initializer for the EOSortOrdering class.

See also:	+ sortOrderingWithKey:selector:

key

− (NSString *)key

Returns the key by which the receiver orders items.

See also:	− selector

selector

− (SEL)selector

Returns the method selector used to compare values when sorting.

See also:	− key


EOTemporaryGlobalID

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	EOGlobalID : NSObject

Conforms To:	NSCoding

NSCopying (EOGlobalID)

NSObject (NSObject)

Declared In:	EOControl/EOGlobalID.h

Class Description

An EOTemporaryGlobalID identifies a newly created object before it’s saved to an external store. When the object is saved, the temporary ID is converted to a permanent one, as described in the EOGlobalID class specification.

Note:	EOTemporaryGlobalID adopts the NSCoding protocol to support identification of newly created objects between a client and server. Even so, an instance doesn’t represent a globally unique ID; it must be replaced with a permanent ID in both the client and the server when the object it identifies is made persistent.

Adopted Protocols

NSCoding	− encodeWithCoder:

− initWithCoder:

Instance Methods

init

− (id)init

Initializes a newly allocated EOTemporaryGlobalID as a unique instance. See the EOGlobalID class description for more information.

isTemporary

− (BOOL)isTemporary

Returns YES.


EOUndoManager

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	NSObject

Conforms To:	NSObject (NSObject)

Declared In:	EOControl/EOUndoManager.h

Class Description

EOUndoManager is a general purpose recorder of operations for undo and redo. You register an undo operation by specifying the object that’s changing (or the owner of that object), along with a method to invoke to revert its state, and the arguments for that method. EOUndoManager automatically groups all operations within a single cycle of the run loop, so that performing an undo reverts all changes that occurred during the loop. Also, when performing undo an EOUndoManager saves the operations reverted so that you can redo the undos.

Operations and Groups

An undo operation is a method for reverting a change to an object, along with the arguments needed to revert the change (for example, its state before the change). Undo operations are typically collected into undo groups, which represent whole undoable actions. Redo operations and groups are simply undo operations stored on a separate stack (described below). When an EOUndoManager performs undo or redo, it’s actually undoing or redoing an entire group of operations. To undo a single operation, it must be packaged in a group.

EOUndoManager normally creates undo groups automatically during the run loop. The first time it’s asked to record an undo operation in the run loop, it creates a new group. Then, at the end of the loop, it closes the group. You can create additional, nested undo groups within these default groups using the beginUndoGrouping and endUndoGrouping methods. You can also turn off the default grouping behavior using setGroupsByEvent:.

The Undo and Redo Stacks

Undo groups are stored on a stack, with the oldest groups at the bottom and the newest at the top. The undo stack is unlimited by default, but you can restrict it to a maximum number of groups using the setLevelsOfUndo: method. When the stack exceeds the maximum, the oldest undo groups are dropped from the bottom.

Initially, both stacks are empty. Recording undo operations adds to the undo stack, but the redo stack remains empty until undo is performed. Performing undo causes the undo operations in the latest group to be applied to their objects. Since these operations cause changes to the objects’ states, the objects presumably register new operations with the EOUndoManager, this time in the reverse direction from the original operations. Since the EOUndoManager is in the process of performing undo, it records these operations as redo operations on the redo stack. Consecutive undos add to the redo stack. Subsequent redo operations pull the operations off the redo stack and apply them to the objects.

The redo stack’s contents last as long as undo and redo is performed. However, because applying a new change to objects invalidates the previous changes, as soon as a new undo operation is registered, the redo stack is cleared. This prevents redo from returning objects to an inappropriate prior state. You can check for the ability to undo and redo with the canUndo and canRedo methods.

Registering Undo Operations

EOUndoManager supports two types of undo operations: one based on a simple selector with a single object argument, and one based on a general NSInvocation (which allows any number and type of arguments). The first method is commonly used by EOEditingContext for changes to enterprise objects. When an object changes, the EOEditingContext records a simple undo operation with an NSDictionary containing the old property values of the object. Performing undo then applies this object snapshot via the key-value coding protocol’s takeValues:forKeys: method. Invocation-based undo is useful for undoing specific state-changing methods, such as a document object’s setFont:color:. This more general undo operation is useful for already-defined methods, especially when their arguments aren’t objects.

Regardless of the type of operations recorded, a single instance of EOUndoManager typically belongs to a single document or container of objects, called the EOUndoManager’s client. Each EOEditingContext in an application, for example, has its own private EOUndoManager. This keeps each pair of undo and redo stacks separate so that when an undo is performed, it applies to the focal document in the application (typically the one displayed in the key window). It also relieves the individual objects from having to know the identity of their EOUndoManager.

In order to use undo effectively, either the client must claim exclusive right to alter its undoable objects—in order to record undo operations for all changes—or the objects themselves must participate in recording their changes. The first case is exemplified by a text document that holds a private NSTextView, handling all text operations by registering undo operations and forwarding the change to the NSTextView. For the second case, the willChange method defined by Enterprise Objects Framework allows any object to notify observers that it’s about to change. EOEditingContexts, being containers for enterprise objects, receive these change notifications and record undo operations (among many other things). Even in this case, interaction with the EOUndoManager is handled exclusively by the container object.

Simple Undo

To record a simple undo operation, you need only invoke registerUndoWithTarget:selector:arg:, giving the object to be sent the undo operation selector, the selector to invoke, and an argument to pass with that message. The target object is rarely the actual object whose state is changing; instead, it’s the client object, a document or container that holds many undoable objects. An object like EOEditingContext, for example, can record an undo operation for insertObject: by registering a deleteObject: message with the object inserted (undoManager is an instance variable):

[undoManager registerUndoWithTarget:self selector:@selector(deleteObject:)

    arg:anObject];

An update might be recorded for undo like so:

NSDictionary *updateDict = [NSDictionary dictionaryWithObjectsAndKeys:anObject,

    @"object", [anObject snapshot], @"snapshot"];

[undoManager registerUndoWithTarget:self

    selector:@selector(revertUpdate:)

    arg:updateDict];

This fragment is likely to be executed as a result of anObject invoking the standard willChange method, which announces that the object’s state is going to change. Since it hasn’t changed yet, the state can be recorded for later undo. This fragment, then, registers the client (self) to be sent a revertUpdate: message with the object and its old state when undo is performed. The old values are retrieved with a snapshot message. revertUpdate: can be implemented to pass the old state back to the object:

- (void)revertUpdate:(NSDictionary *)updateDict

{

    [[updateDict objectForKey:@"object"]

        udpateFromSnapshot:[updateDict objectForKey:@"snapshot"]];

    return;

}

Both snapshot and updateFromSnapshot: are methods added to NSObject by the Framework. See the NSObject Additions specification for more information.

Invocation-Based Undo

For other changes involving specific methods or arguments that aren’t objects, you can use invocation-based undo, which records an actual message to revert the target object’s state. As with simple undo, you record a message that reverts the object to its state before the change. However, in this case you do so by sending the message directly to the EOUndoManager, after preparing it with a special message to note the target:

[[myUndoManager prepareWithInvocationTarget:textObject]

    setFont:[textObject font] color:[textObject textColor]];

[textObject setFont:newFont color:newColor];

prepareWithInvocationTarget: records the argument as the target of the undo operation about to be established. Following this, you send the message that will revert the target’s state—in this case, setFont:color:. Because EOUndoManager doesn’t respond to this method, forwardInvocation: is invoked, which EOUndoManager implements to record the NSInvocation containing the target, selector, and all arguments. Performing undo later results in textObject being sent a setFont:color: message with the old values.

Performing Undo and Redo

Performing undo and redo is usually as simple as sending undo and redo messages to the EOUndoManager. undo closes the last open undo group and then applies all of the undo operations in that group (recording any undo operations as redo operations instead). redo likewise applies all of the redo operations on the top redo group.

undo is intended for undoing top-level groups, and shouldn’t be used for nested undo groups. If any unclosed, nested undo groups are on the stack when undo is invoked, it raises an exception. To undo nested groups, you must use explicitly close the group with an endUndoGrouping message, then use undoNestedGroup to undo it. Note also that if you turn off automatic grouping by event with setGroupsByEvent:, you must explicitly close the current undo group with endUndoGrouping before invoking either undo method.

Cleaning the Undo Stack

EOUndoManager doesn’t retain the targets of undo operations, for several reasons. Foremost is that the client—the object registering operations—typically owns the EOUndoManager, so retaining it would create cycles. The EOUndoManager does contain references to the targets of undo operations, however, which it uses to send undo messages when undo is performed. If a target object has been deallocated, this will cause errors.

To remedy this, the client must take care to clear undo operations for targets that are being deallocated. This typically occurs in one of three ways:

•	The client is the exclusive owner of the EOUndoManager and the target of all undo operations. In this case the client can simply release the EOUndoManager in its dealloc method.

•	The client shares the EOUndoManager with other clients. To handle this the client should send forgetAllWithTarget: to the EOUndoManager before releasing it in its dealloc method.

•	The client registers objects other than itself for undo operations. Here either the client must watch for the other objects being deallocated in order to send forgetAllWithTarget:, or the other objects must do so themselves when deallocated (which requires that they have a reference to the EOUndoManager). This is likely to be needed with invocation-based undo.

In a more general sense, it sometimes makes sense to clear all undo and redo operations. Some applications might want to do this when saving a document, for example. To this end, EOUndoManager defines the forgetAll method, which clears both stacks.

Undo Checkpoint Notifications

Objects sometimes delay performing changes, for various reasons. This means they may also delay registering undo operations for those changes. Because EOUndoManager collects individual operations into groups, it must be sure to synchronize its client with the creation of these groups so that operations are entered into the proper undo groups. To this end, whenever an EOUndoManager opens or closes a new undo group (except when it opens a top-level group), it posts an EOUndoManagerCheckpointNotification so that observers can apply their pending undo operations to the group in effect. The EOUndoManager’s client should register itself as an observer for this notification and record undo operations for all pending changes upon receiving it.

Method Types

Registering undo operations	− registerUndoWithTarget:selector:arg:

− prepareWithInvocationTarget:

− forwardInvocation:

Checking undo ability	− canUndo

− canRedo

Performing undo and redo	− undo

− undoNestedGroup

− redo

Limiting the undo stack	− setLevelsOfUndo:

− levelsOfUndo

Creating undo groups	− beginUndoGrouping

− endUndoGrouping

− setGroupsByEvent:

− groupsByEvent

Disabling undo	− disableUndoRegistration

− reenableUndoRegistration

Checking whether undo or redo is being performed

− isUndoing

− isRedoing

Clearing undo operations	− forgetAll

− forgetAllWithTarget:

Instance Methods

beginUndoGrouping

− (void)beginUndoGrouping

Marks the beginning of an undo group. All individual undo operations before a subsequent endUndoGrouping message are grouped together and reversed by a later undo message. Undo groups can be nested, thus providing functionality similar to nested transactions.

This method posts an EOUndoManagerCheckpointNotification.

canRedo

− (BOOL)canRedo

Returns YES if the receiver has any actions to redo, NO if it doesn’t.

Because any undo operation registered clears the redo stack, this method posts an EOUndoManagerCheckpointNotification to allow clients to apply their pending operations before testing the redo stack.

See also:	− canUndo, − redo

canUndo

− (BOOL)canUndo

Returns YES if the receiver has any actions to undo, NO if it doesn’t. This does not mean that you can safely invoke undo or undoNestedGroup; you may have to close open undo groups first.

See also:	− canRedo, − endUndoGrouping, − registerUndoWithTarget:selector:arg:

disableUndoRegistration

− (void)disableUndoRegistration

Disables the recording of undo operations, whether by registerUndoWithTarget:selector:arg: or by invocation-based undo. This method can be invoked multiple times; reenableUndoRegistration must be invoked an equal number of times to actually reenable undo registration.

endUndoGrouping

− (void)endUndoGrouping

Marks the end of an undo group. All individual undo operations back to the matching beginUndoGrouping message are grouped together and reversed by a later undo or undoNestedGroup message. Undo groups can be nested, thus providing functionality similar to nested transactions. Raises an NSInternalInconsistencyException if there’s no beginUndoGrouping message in effect.

This method posts an EOUndoManagerCheckpointNotification.

See also:	− levelsOfUndo

forgetAll

− (void)forgetAll

Clears the undo and redo stacks and reenables the receiver.

See also:	− reenableUndoRegistration, − forgetAllWithTarget:

forgetAllWithTarget:

− (void)forgetAllWithTarget:(id)target

Clears the undo and redo stacks of all operations involving target as the recipient of the undo message. Doesn’t reenable the receiver if it’s disabled. An object that shares an EOUndoManager with other clients should invoke this message in its implementation of dealloc.

See also:	− reenableUndoRegistration, − forgetAll

forwardInvocation:

− (void)forwardInvocation:(NSInvocation *)anInvocation

Overrides NSObject’s implementation to record anInvocation as an undo operation. Also clears the redo stack. Raises an NSInternalInconsistencyException if prepareWithInvocationTarget: wasn’t invoked before this method; this method then clears the prepared invocation target. See “Invocation-Based Undo” in the class description for more information.

Raises an NSInternalInconsistencyException if invoked when no undo group has been established using beginUndoGrouping. Undo groups are normally set by default, so you should rarely need to begin a top-level undo group explicitly.

See also:	− undoNestedGroup, − registerUndoWithTarget:selector:arg:, − groupsByEvent

groupsByEvent

− (BOOL)groupsByEvent

Returns YES if the receiver automatically creates undo groups around each pass of the run loop, NO if it doesn’t. The default is YES.

See also:	− beginUndoGrouping, − setGroupsByEvent:

isUndoing

− (BOOL)isUndoing

Returns YES if the receiver is in the process of performing its undo or undoNestedGroup method, NO otherwise.

See also:	− isRedoing

isRedoing

− (BOOL)isRedoing

Returns YES if the receiver is in the process of performing its redo method, NO otherwise.

See also:	− isUndoing

levelsOfUndo

− (unsigned int)levelsOfUndo

Returns the maximum number of top-level undo groups the receiver will hold. When ending an undo group results in the number of groups exceeding this limit, the oldest groups are dropped from the stack. A limit of zero indicates no limit, so that old undo groups are never dropped. The default is zero.

See also:	− endUndoGrouping, − setLevelsOfUndo:

prepareWithInvocationTarget:

− (id)prepareWithInvocationTarget:(id)target

Prepares the receiver for invocation-based undo with target as the subject of the next undo operation and returns self. See “Invocation-Based Undo” in the class description for more information.

See also:	− forwardInvocation:

redo

− (void)redo

Performs the operations in the last group on the redo stack, if there are any, recording them on the undo stack as a single group.

This method posts an EOUndoManagerCheckpointNotification.

See also:	− redo, − registerUndoWithTarget:selector:arg:

reenableUndoRegistration

− (void)reenableUndoRegistration

Balances a prior disableUndoRegistration message. Undo registration isn’t actually reenabled until a reenable message balances the last disable message in effect. Raises an NSInternalInconsistencyException if invoked while no disableUndoRegistration message is in effect.

registerUndoWithTarget:selector:arg:

− (void)registerUndoWithTarget:(id)target selector:(SEL)aSelector arg:(id)anObject

Records a single undo operation for target, so that when undo is performed it’s sent aSelector with anObject as the sole argument. Also clears the redo stack. Doesn’t retain target. See “Simple Undo” in the class description for more information.

Raises an NSInternalInconsistencyException if invoked when no undo group has been established using beginUndoGrouping. Undo groups are normally set by default, so you should rarely need to begin a top-level undo group explicitly.

See also:	− undoNestedGroup, − forwardInvocation:, − groupsByEvent

setGroupsByEvent:

− (void)setGroupsByEvent:(BOOL)flag

Sets whether the receiver automatically groups undo operations during the run loop. If flag is YES, the receiver creates undo groups around each pass through the run loop; if flag is NO it doesn’t. The default is YES.

If you turn automatic grouping off, you must close groups explicitly before invoking either undo or undoNestedGroup.

See also:	− groupsByEvent

setLevelsOfUndo:

− (void)setLevelsOfUndo:(unsigned int)anInt

Sets the maximum number of top-level undo groups the receiver will hold to anInt. When ending an undo group results in the number of groups exceeding this limit, the oldest groups are dropped from the stack. A limit of zero indicates no limit, so that old undo groups are never dropped. The default is zero.

If invoked with a limit below the prior limit, old undo groups are immediately dropped.

See also:	− endUndoGrouping, − levelsOfUndo

undo

− (void)undo

Closes the top-level undo group if necessary and invokes undoNestedGroup. Raises an NSInternalInconsistencyException if more than one undo group is open (that is, if the last group isn’t at the top level).

This method posts an EOUndoManagerCheckpointNotification.

See also:	− endUndoGrouping, − groupsByEvent

undoNestedGroup

− (void)undoNestedGroup

Performs the undo operations in the last undo group (whether top-level or nested), recording the operations on the redo stack as a single group. Raises an NSInternalInconsistencyException if any undo operations have been registered since the last endUndoGrouping message.

This method posts an EOUndoManagerCheckpointNotification.

See also:	− undo

Notifications

EOUndoManagerCheckpointNotification

Posted whenever an EOUndoManager opens or closes an undo group (except when it opens a top-level group), and when checking the redo stack in canRedo. The notification contains:

Notification Object	The EOUndoManager

Userinfo	nil


NSArray Additions

Cop  Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Class Cluster Description

Enterprise Objects Framework adds a few methods to the Foundation Framework’s NSArray class cluster, for filtering objects according to an EOQualifier and sorting them according to a series of EOSortOrderings.

NSArray

Inherits From:	NSObject

Declared In:	EOControl/EOQualifier.h

EOControl/EOSortOrdering.h

Class Description

Enterprise Objects Framework adds two methods to the Foundation Framework’s NSArray class, for filtering objects according to an EOQualifier and sorting them according to a series of EOSortOrderings.

Method Types

filteredArrayUsingQualifier:

− (NSArray *)filteredArrayUsingQualifier:(EOQualifier *)aQualifier

Returns a new NSArray that contains only the objects from the receiver matching aQualifier.

sortedArrayUsingKeyOrderArray:

− (NSArray *)sortedArrayUsingKeyOrderArray:(NSArray *)orderings

Creates and returns a new NSArray by sorting the objects of the receiver according to the EOSortOrderings in orderings. The objects are compared by extracting the sort properties using the added NSObject method valueForKey: and sending them compare: messages.

See also:	− sortUsingKeyOrderArray: (NSMutableArray)

NSMutableArray

Inherits From:	NSObject

Declared In:	EOControl/EOSortOrdering.h

NSMutableArray has one added method for sorting its elements according to a series of EOSortOrderings.

Instance Methods

sortUsingKeyOrderArray:

− (void)sortUsingKeyOrderArray:(NSArray *)orderings

Sorts the objects of the receiver according to the EOSortOrderings in orderings. The objects are compared by extracting the sort properties using the added NSObject method valueForKey: and sending them compare: messages.

See also:	− sortedArrayUsingKeyOrderArray: (NSArray)


NSException Additions

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	NSObject

Declared In:	EOControl/EOClassDescription.h

Class Description

Enterprise Objects Framework adds two methods to the Foundation Framework’s NSException class, both used primarily for validation errors. Of the two, you typically use only validationExceptionWithFormat: in an enterprise object’s validateFor... or validateProperty: method, as described in the NSObject Additions class specification. The other method, aggregateExceptionWithExceptions:, is used internally by the Framework to group multiple validation exceptions together.

Method Types

Creating a validation exception	+ validationExceptionWithFormat:

Collecting exceptions	+ aggregateExceptionWithExceptions:

Class Methods

aggregateExceptionWithExceptions:

+ (NSException *)aggregateExceptionWithExceptions:(NSArray *)exceptions

Returns the first NSException in exceptions, with the remaining exceptions collected in its userInfo dictionary as an NSArray under the key EOAdditionalExceptionsKey.

validationExceptionWithFormat:

+ (NSException *)validationExceptionWithFormat:(NSString *)format, ...

Returns an NSException whose name is EOValidationException and whose reason is an NSString created from format and subsequent arguments.


NSObjectAdditions

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	none (NSObject is a root class)

Declared In:	EOControl/EOClassDescription.h

EOControl/EOEditingContext.h

EOControl/EOKeyValueCoding.h

EOControl/EOObserver.h

Purpose

Defines basic functionality for all enterprise objects.

Principal Attributes

•	EOClassDescription

Creation

− init	Designated initializer.

− initWithEditingContext:classDescription:globalID:	Optional initializer.

− awakeFromFetchInEditingContext:	Additional initialization after being fetched.

− awakeFromInsertionInEditingContext:	Additional initialization after being created in memory.

Commonly Used Methods

− willChange	Notifies observers of a change in state.

− editingContext	Returns the receiver’s EOEditingContext.

− addObject:toPropertyWithKey:	Adds an object to a relationship property.

− removeObject:fromPropertyWithKey:	Removes an object from a relationship property.

− addObject:toBothSidesOfRelationshipWithKey:	Adds an object to a relationship property and the receiver to the reciprocal relationship.

− removeObject:fromBothSidesOfRelationshipWithKey:

Removes an object from a relationship property and the receiver from the reciprocal relationship.

Methods to Implement or Override

These methods are invoked by the Framework to

− setKey:	Sets the value for the property named key.

− key	Retrieves the value for the property named key.

− addToKey:	Adds a value to a relationship property named key.

− removeFromKey:	Removes a value from the property named key.

− handleTakeValue:forUnboundKey:	Handles a failure of takeValue:forKey: to find a property.

− handleQueryWithUnboundKey:	Handles a failure of valueForKey: to find a property.

− unableToSetNilForKey:	Handles an attempt to set a non-object property’s value to nil.

− validateKey:	Validates a value for the property named key.

− validateForDelete	Validates all properties before deleting the receiver.

− validateForInsert	Validates all properties before inserting the receiver.

− validateForSave	Validates all properties before saving the receiver.

− validateForUpdate	Validates all properties before updating the receiver.

Class Description

Enterprise Objects Framework adds a number of methods to NSObject for supporting operations common to all enterprise objects. Among these are methods for initializing instances, announcing changes, setting and retrieving property values, and performing validation of state. Some of these methods are for enterprise objects to implement or override, and some are meant to be used as defined by the Framework. Many methods are used internally by the Framework and rarely invoked by application code. The implementation or use of each method is highlighted in the following sections, which describe the major functional groups.

Initialization Methods

Enterprise objects are initialized using the initWithEditingContext:classDescription:globalID:, which by default simply invokes init. You can place your custom initialization code in init, or you can override initWithEditingContext:classDescription:globalID: to take advantage of the extra information available with this method.

After initialization, an enterprise object receives an awake... message. The particular message depends on whether the object has been fetched from a database or created anew in the application. In the former case, it receives an awakeFromFetchInEditingContext: message. In the latter, it receives an awakeFromInsertionInEditingContext: message. The receiver can override either method to perform extra initialization—such as setting default values—based on how it was created.

Announcing Changes

For the Framework to keep all areas of an application synchronized, enterprise objects must notify their observers when their state changes. Objects do this by simply invoking willChange before altering any instance variable or other kind of state. This method informs all observers that the invoker is about to change. See the EOObserverCenter class specification for more information on change notification.

The primary observer of changes in an object is its EOEditingContext. EOEditingContext is a subclass of EOObjectStore that manages collections of objects in memory, tracking inserts, deletes, and updates, and propagating changes to the persistent store as needed. You can get the EOEditingContext that contains an object by sending the object an editingContext message.

Getting Object and Class Metadata

One of the larger groups of methods added to NSObject provides information about an object’s properties. Most of these methods consult an EOClassDescription to provide their answers. The classDescription method return an object’s EOClassDescription. See that class specification for the methods it implements. Methods you can send directly to any object include entityName, which provides the name of the entity mapped to the receiver’s class; allPropertyKeys, which returns the names of all the receiver’s class properties, attributes and relationships alike; and attributeKeys, which returns just the names of the attributes.

Some methods return information about relationships. toOneRelationshipKeys and toManyRelationshipKeys return the names of the receiver’s relationships, while isToManyKey: tells which kind a particular relationship is. deleteRuleForRelationshipKey: indicates what should happen to the receiver’s relationships when it’s deleted. Similarly, ownsDestinationObjectsForRelationshipKey: indicates what should happen when another object is added to or removed from the receiver’s relationship. Another method, classDescriptionForDestinationKey:, returns the EOClassDescription for the destination of a relationship.

These methods are all properly implemented in terms of the receiver’s EOClassDescription, so unless your object class doesn’t have an EOClassDescription, there’s little need to override them. One method you might override in your enterprise object class, however, is inverseForRelationshipKey:. Given the name of one of the receiver’s relationships, this method finds the destination object’s class data and determines the name of the relationship that points back at the receiver. The default implementation of this method looks for a relationship predicated on the same attributes in both the source and destination, which works correctly in most cases. If, however, you define a reciprocal pair of relationships on different attributes, you should override this method to take that into account. See the method description for an example.

Key-Value Coding Methods

A special set of methods form the Framework’s main data transport mechanism, in which the properties of an enterprise object are accessed indirectly by name (or key), rather than directly through invocation of an accessor method or as instance variables. Thus, any object’s state can be accessed in a consistent manner.

The basic methods for accessing an enterprise object’s values are takeValue:forKey: and valueForKey:. These two methods are defined by NSObject to use the accessor methods normally implemented by objects (or to access instance variables directly if need be), so that you don’t have to write special code simply to integrate your enterprise objects into the Framework. Another pair of methods, takeValuesFromDictionary: and valuesForKeys:, gives access to groups of properties. Lastly, valueForKeyPath: and valueForKeyPath: give access to flattened properties, of the form relationship.property; for example, “department.name”.

Default Implementations; Handling Access Errors

The Framework provides default implementations of takeValue:forKey: and valueForKey: that work for all objects. The other four access methods are implemented in terms of these two. These implementations are general enough that your enterprise object classes should rarely need to override either key-value coding method. In accessing an object’s property, the default NSObject implementations of the key-value coding methods use the class definition as follows:

1.	The key-value coding method looks for an accessor method based on the key. For example, with a key of “lastName”, takeValue:forKey: looks for a method named setLastName: (note that the first letter of the property name is made uppercase), and valueForKey: looks for a method of the form lastName.

2.	If the key-value coding method doesn’t find an accessor method, and the class responds YES to an accessInstanceVariablesDirectly message (which it does by default), it looks for an instance variable whose name is the same as the key and sets or retrieves its value directly. In setting an instance variable that’s an object, takeValue:forKey: retains the new value and autoreleases the old one.

3.	If neither an accessor method nor an instance variable can be found, the default implementations invoke methods that your custom objects can override to handle failures. handleTakeValue:forUnboundKey: is invoked from takeValue:forKey:, and handleQueryWithUnboundKey: is invoked from valueForKey:. Normally these methods raise an exception, but you can implement them to set or get a value in whatever way is needed.

The key-value coding methods cache attribute bindings for both accessor methods and instance variables, making lookups efficient. If you need to clear these bindings—as when you add or remove a class from the run-time system—you can invoke flushKeyBindings to do so.

Some subclasses of NSObject override the default implementations. EOGenericRecord’s implementations, for example, simply store nd retrieve the properties in an NSDictionary object held by the EOGenericRecord. NSDictionary and NSMutableDictionary, though not suitable for use as enterprise objects, meaningfully implement these methods by directly accessing their key-value pairs.

Type Checking and Type Conversion

The default implementations of the key-value coding methods accept any object as a value, and do no type checking or type conversion among object classes. It’s possible, for example, to pass an NSString to takeValue:forKey: as the value for a property the receiver expects to be an NSDate. The sender of a key-value coding message is thus responsible for ensuring that a values is of the proper class, typically by using the validateValue:forKey: method to coerce it to the proper type. The interface layer’s EODisplayGroup uses this on all values received from interface user objects, for example, as well as relying on number and date formatters to interpret string values typed by the user. For more information on the validateValue:forKey: method, see the EOClassDescription and EOEntityClassDescription class specifications.

The key-value coding methods handle one special case with regard to value types. For enterprise objects that access numeric values as C scalar types, these methods automatically convert between the scalar types and NSNumber objects. For example, suppose your enterprise object defines these accessor methods:

− (void)setSalary:(unsigned int)salary

− (unsigned int)salary

For the setSalary: method, takeValue:forKey: converts the object value for the “salary” key in the dictionary to an unsigned int and passes it as salary. Similarly, valueForKey: converts the return value of the salary method to an NSNumber and returns that.

The default implementations support the following scalar types:

char	unsigned char

short	unsigned short

int	unsigned int

long	unsigned long

float	double

Object values are converted to these types with the standard messages charValue, intValue, floatValue, and so on. Note that the key-value coding methods don’t check that an object value actually responds to these messages; this can result in a run-time error if the object doesn’t respond to the appropriate message.

One type of conversion these methods can’t perform is that from a nil object value to a scalar value. C scalar values define no equivalent of a database system’s NULL value, so these must be handled by the object itself. Upon encountering an nil while setting a scalar value, the takeValue:forKey: invokes unableToSetNilForKey:, which by default simply raises an exception. Enterprise object classes that use scalar values which may be NULL in the database should override this method to substitute the appropriate scalar value for nil, reinvoking takeValue:forKey: to set the substitute value. This method works in general to handle setting scalar properties to nil.

EONull in Collections

Because collection objects such as NSArray and NSDictionary can’t contain nil as a value, it must represented by a special object, EONull. EONull provides a single instance that represents the NULL value for object attributes. The default implementations of takeValuesFromDictionary: and valuesForKeys: translate EONull and nil between NSDictionaries and enterprise objects, removing the need for your objects to explicitly test for EONull values.

Relationship Accessor Methods

Building on the key-value coding methods, another group of methods allows you to modify relationship properties by adding and removing single objects, rather than replacing the entire content of the relationship, and to modify relationships so that reciprocal relationships are automatically adjusted. addObject:toPropertyWithKey: and removeObject:fromPropertyWithKey: handle the first situation, doing all the work of altering arrays for to-many relationships. They both check first for a method you might implement, addToKey: or removeFromKey:, invoking that method if it’s implemented, otherwise using the basic key-value coding methods to do the work.

Reciprocal relationships are handled by addObject:toBothSidesOfRelationshipWithKey: and removeObject:fromBothSidesOfRelationshipWithKey:. For example, when you add an Employee to a Department’s employees relationship, or remove it, you also want the Employee’s department relationship altered to suit. These two methods take care of tracing the inverse relationship and use addObject:toPropertyWithKey: and removeObject:fromPropertyWithKey: to alter both relationships, whether they’re to-one or to-many. Unless you have specific reasons to do otherwise, you should always use the methods that handle reciprocal relationships so that back pointers are properly updated.

Two other methods that affect relationships are typically used internally by the Framework. You should rarely have a need either to invoke or override them. propagateDeleteWithEditingContext: applies an object’s delete rule to the destinations of its relationships. The delete rule specifies whether a destination object should be ignored, also deleted, or whether the deletion should be disallowed if a destination exists. clearProperties simply sets all of the receiver’s relationship properties to nil. EOEditingContexts use this method to break circular references when they’re deallocated.

Snapshots

The key-value coding methods define a general mechanism for accessing an object’s properties, but you first have to know what those properties are. Sometimes, however, you just want to preserve an object’s entire state for later use, whether to undo changes to the object, compare the values that have changed, or just keep a record of the changes. The snapshotting methods provide this service, extracting or setting all properties at once and performing the necessary conversions for proper behavior. snapshot returns an NSDictionary containing all the receiver’s properties, with EONull substituted for nil and arrays reproduced as shallow, immutable copies. updateFromSnapshot: sets properties of the receiver to the values in a snapshot, converting EONull to nil, and making shallow, mutable copies of any array values (allowing the object to add to and remove from the array).

Validation

Validating new values is a vital part of business logic. Several methods added to NSObject support validation at different stages of an object’s life. Validation methods check for illegal value types, values outside of established limits, illegal relationships, and so on. All validation methods return nil if the values under consideration are valid, or an NSException indicating how the values aren’t valid.

There are two kinds of validation methods that you can override. The first covers individual properties, when it’s important to validate a value before it changes. These methods are invoked automatically by the Framework when it changes a property value, such as when the user makes an edit in the user interface. These methods are dynamically invoked based on the property name. The second kind covers operations to the external store—inserting, updating, and deleting. These methods are invoked when the associated operation is performed. You can override these methods in your custom enterprise object classes to perform delayed validation of properties, to compare multiple properties against one another, and to allow or refuse the operation based on property values. For example, a Fee object might refuse to be deleted if it hasn’t been paid yet.

Immediate Validation of Individual Properties

The most general method, validateValue:forKey:, is used by the Framework when an EODisplayGroup passes an updated value to the object and when the object is saved. This method does two things: coerce the value into an appropriate type for the object, and validate it according to the object’s rules. Coercion is performed automatically for you, so all you need handle is validation itself.

The default implementation of validateValue:forKey: consults the object’s EOClassDescription for basic errors, such as a nil value when that isn’t allowed. If no basic errors exist, this method then examines the object’s class itself for a method of the form validateKey: and invokes that. These are the methods that your custom classes can implement to validate individual properties, such as validateAge: to check that the value the user entered is within acceptable limits.

For example, suppose that Member objects have an age attribute stored as an integer. This attribute has an lower limit of 16, defined by the Member class. Now, suppose the user types “12” into a text field for the age. Before the EODisplayGroup updates the selected object, it sends the object a validateValue:forKey: message. The object uses its EOEntityClassDescription to convert the string “12” into an NSNumber, then invokes validateAge: with that NSNumber. Member’s implementation of this method compares the age to its limit of 16 and returns an EOValidationException:

- (NSException *)validateAge:(NSNumber *)age

{

    if ([age intValue] < 16) {

        return [NSException

            validationExceptionWithFormat:@"Age of %@ is below minimum.", age];

    }

    return nil;

}

The Framework adds the validationExceptionWithFormat: method to NSException for convenient creation of validation exceptions.

Validation for Specific Operations

The other validation methods are invoked at specific times—such as before the object is written to or deleted from the external store—and are particularly useful when properties must be compared or when calculation is necessary. The methods are validateForInsert, validateForUpdate, validateForSave, and validateForDelete, and they’re invoked automatically for the operations indicated by the method name. You can override these methods to check values individually or in groups; for example, you might verify that a pair of dates is in the proper temporal order:

- (NSException *)validateForSave

{

    if ([startDate compare:endDate] == NSOrderedDescending) {

        return [NSException

            validationExceptionWithFormat:@"Start date must not follow end date."];

    }

    return [super validateForSave];

}

Note that this method also invokes super’s implementation. This is important, as the default implementations of the validateFor... pass the check on to the object’s EOClassDescription, which performs basic checking among properties. The access layer’s EOEntityClassDescription class verifies constraints based on an EOModel, such as delete rules. For example, the delete rule for a Department object might state that it can’t be deleted if it still contains Employee objects.

validateForSave is the generic validation method for when an object is written to the external store. The default implementations of validateForInsert and validateForUpdate both invoke this method. If an object performs validation that isn’t specific to insertion or to updating, it should go in validateForSave.

Method Types

Initializing enterprise objects	− initWithEditingContext:classDescription:globalID:

− awakeFromFetchInEditingContext:

− awakeFromInsertionInEditingContext:

Announcing changes	− willChange

Getting an object’s EOEditingContext

− editingContext

Getting class description information	− allPropertyKeys

− attributeKeys

− classDescription

− classDescriptionForDestinationKey:

− deleteRuleForRelationshipKey:

− entityName

− inverseForRelationshipKey:

− isToManyKey:

− ownsDestinationObjectsForRelationshipKey:

− toManyRelationshipKeys

− toOneRelationshipKeys

Key-value coding	− takeValue:forKey:

− valueForKey:

− takeValuesFromDictionary:

− valuesForKeys:

− takeValue:forKeyPath:

− valueForKeyPath:

− handleQueryWithUnboundKey:

− handleTakeValue:forUnboundKey:

− unableToSetNilForKey:

+ accessInstanceVariablesDirectly

− flushKeyBindings

Modifying relationships	− addObject:toPropertyWithKey:

− removeObject:fromPropertyWithKey:

− addObject:toBothSidesOfRelationshipWithKey:

− removeObject:fromBothSidesOfRelationshipWithKey:

− propagateDeleteWithEditingContext:

− clearProperties

Working with snapshots	− snapshot

− updateFromSnapshot:

Validating values	− validateForDelete

− validateForInsert

− validateForSave

− validateForUpdate

− validateValue:forKey:

Getting descriptions	− eoDescription

− eoShallowDescription

Class Methods

accessInstanceVariablesDirectly

+ (BOOL)accessInstanceVariablesDirectly

Returns YES if the default implementations of the key-value coding methods, on finding no accessor method for a property, should access the corresponding instance variable directly. Returns NO if they shouldn’t. NSObject’s implementation of this method returns YES. Subclasses can override it to return NO, in which case the other methods won’t access instance variables.

Instance Methods

addObject:toBothSidesOfRelationshipWithKey:

− (void)addObject:(id)anObject toBothSidesOfRelationshipWithKey:(NSString *)key

Sets or adds anObject as the destination for the receiver’s relationship identified by key, and also sets or adds the receiver for anObject’s reciprocal relationship if there is one. For a to-one relationship, anObject is set using takeValue:forKey:. For a to-many relationship, anObject is added using addObject:toPropertyWithKey:.

This method also properly handles removing self and anObject from their previous relationship as needed. For example, if an Employee object belongs to the Research department, invoking this method with the Maintenance department removes the Employee from the Research department as well as setting the Employee’s department to Maintenance.

See also:	− removeObject:fromBothSidesOfRelationshipWithKey:

addObject:toPropertyWithKey:

− (void)addObject:(id)anObject toPropertyWithKey:(NSString *)key

Adds anObject to the receiver’s to-many relationship identified by key, without setting any reciprocal relationship. Similar to takeValue:forKey:, this method first attempts to invoke a method of the form addToKey:. If the receiver doesn’t have such a method, this method gets the property array using valueForKey: and operates directly on that.

If the array is mutable, this method simply adds anObject using addObject:. Otherwise it constructs a new array containing any existing objects and anObject, then sets it using takeValue:forKey:.

See also:	− removeObject:fromPropertyWithKey:, − addObject:toBothSidesOfRelationshipWithKey:

allPropertyKeys

− (NSArray *)allPropertyKeys

Returns all of the receiver’s property keys, as returned by attributeKeys, toOneRelationshipKeys, and toManyRelationshipKeys.

attributeKeys

− (NSArray *)attributeKeys

Returns the names of the receiver’s attributes, as determined from the EOClassDescription. You might wish to override this method to add keys for attributes not defined by the EOClassDescription. The access layer’s subclass of EOClassDescription, EOEntityClassDescription, returns the names of attributes designated as class properties.

See also:	− toOneRelationshipKeys, − toManyRelationshipKeys., − attributeKeys (EOClassDescription)

awakeFromFetchInEditingContext:

− (void)awakeFromFetchInEditingContext:(EOEditingContext *)anEditingContext

Overridden by subclasses to perform additional initialization upon being fetched from the external repository into anEditingContext. NSObject’s implementation merely sends an awakeObject:fromFetchInEditingContext: to the receiver’s EOClassDescription. Subclasses should invoke super’s implementation before performing their own initialization.

See also:	− awakeFromInsertionInEditingContext:

awakeFromInsertionInEditingContext:

− (void)awakeFromInsertionInEditingContext:(EOEditingContext *)anEditingContext

Overridden by subclasses to perform additional initialization upon being inserted into anEditingContext. This is commonly used to assign default values or record the time of insertion. NSObject’s implementation merely sends an awakeObject:fromInsertionInEditingContext: to the receiver’s EOClassDescription. Subclasses should invoke super’s implementation before performing their own initialization.

See also:	− awakeFromFetchInEditingContext:

classDescription

− (EOClassDescription *)classDescription

Returns the EOClassDescription registered for the receiver’s class. If none is found, posts an EOClassDescriptionNeededNotification on behalf of the receiver’s class, allowing an observer to register a an EOClassDescription. See the EOClassDescription class specification for more information.

See also:	+ registerClassDescription:forClass: (EOClassDescription)

classDescriptionForDestinationKey:

− (EOClassDescription *)classDescriptionForDestinationKey:(NSString *)key

Returns the EOClassDescription for the destination objects of the relationship identified by key. If none is found, posts an EOClassDescriptionNeededNotification on behalf of the destination objects’ class, allowing an observer to register a an EOClassDescription. See the EOClassDescription class specification for more information.

See also:	+ registerClassDescription:forClass: (EOClassDescription), − classDescriptionForDestinationKey:

clearProperties

− (void)clearProperties

Sets all of the receiver’s to-one and to-many relationships to nil. EOEditingContexts use this method to break circular references among objects when they’re deallocated. You should never need to invoke this method or override it.

See also:	− toOneRelationshipKeys, − toManyRelationshipKeys, − takeValue:forKey:

deleteRuleForRelationshipKey:

− (EODeleteRule)deleteRuleForRelationshipKey:(NSString *)relationshipKey

Returns a rule indicating how to handle the destination of the receiver’s relationship named by relationshipKey when the receiver is deleted. The delete rule is one of:

EODeleteRuleNullify

EODeleteRuleCascade

EODeleteRuleDeny

For example, an Invoice object might return EODeleteRuleCascade for the relationship named “lineItems”, since when an invoice is deleted, its line items should be as well.

See also:	− propagateDeleteWithEditingContext:, − validateForDelete, − deleteRuleForRelationshipKey: (EOClassDescription)

editingContext

− (EOEditingContext *)editingContext

Returns the EOEditingContext that holds the receiver.

entityName

− (NSString *)entityName

Returns the name of the receiver’s entity, or nil if it doesn’t have one.

See also:	− entityName (EOClassDescription)

eoDescription

− (NSString *)eoDescription

Returns a full description of the receiver’s property values by extracting them via the key-value coding methods. An object referenced through relationships is listed with the results of an eoShallowDescription message (to avoid infinite recursion through cyclical relationships).

This method is useful for debugging. You can define your enterprise object’s description method to invoke this one, so that the debugger’s print-object command (po on the command line) automatically displays this description. You can also invoke this method directly on the command line.

See also:	− eoShallowDescription

eoShallowDescription

− (NSString *)eoShallowDescription

Returns a string containing the receiver’s class and entity names, along with the memory address of its id.

See also:	− eoDescription

flushKeyBindings

− (void)flushKeyBindings

Invalidates cached key binding information. Enterprise Objects Framework uses this information to optimize the default implementations of the other methods of this protocol by caching method selectors and instance variable type information.

This method should be invoked whenever a class is modified or removed from the run-time system. It’s invoked automatically when an NSBundle is loaded, however, so you should never need to do so yourself.

handleQueryWithUnboundKey:

− (id)handleQueryWithUnboundKey:(NSString *)key

Invoked from valueForKey: when it finds no property binding for key. NSObject’s implementation raises an NSInvalidArgumentException. Subclasses can override it to handle the query in some other way.

See also:	− handleTakeValue:forUnboundKey:

handleTakeValue:forUnboundKey:

− (void)handleTakeValue:(id)value forUnboundKey:(NSString *)key

Invoked from takeValue:forKey: when it finds no property binding for key. NSObject’s implementation raises an NSInvalidArgumentException. Subclasses can override it to handle the request in some other way.

See also:	− handleQueryWithUnboundKey:

initWithEditingContext:classDescription:globalID:

− initWithEditingContext:(EOEditingContext *)anEditingContext

classDescription:(EOClassDescription *)aClassDescription

globalID:(EOGlobalID *)globalID

Overridden by subclasses to perform initialization with the extra arguments provided. NSObject’s implementation simply invokes init.

See also:	− createInstanceWithEditingContext:classDescription:globalID: (EOClassDescription), − initializeObject:withGlobalID:editingContext: (EOEditingContext), − initializeObject:withGlobalID:editingContext: (EODatabaseContext), − initializeObject:withGlobalID:editingContext: (EOObjectStore)

inverseForRelationshipKey:

− (NSString *)inverseForRelationshipKey:(NSString *)relationshipKey

Returns the name of the relationship pointing back to the receiver’s class or entity from that named by relationshipKey, or nil if there isn’t one. With EOEntity and EORelationship, for example, reciprocality is determined by the join attributes of the two EORelationships.

You might override this method for reciprocal relationships that aren’t defined using the same join attributes. For example, if a Member object has a relationship to CreditCard based on the card number, but a CreditCard has a relationship to Member based on the Member’s primary key, both classes need to override this method. This is how Member might implement it:

- (NSString *)inverseForRelationshipKey:(NSString *)relationshipKey

{

    if ([relationshipKey isEqual:@"creditCard"]) return @"member";

    return [super inverseForRelationshipKey:relationshipKey];

}

See also:	− inverseForRelationshipKey: (EOClassDescription)

isToManyKey:

− (BOOL)isToManyKey:(NSString *)key

Returns YES if the receiver has a to-many relationship identified by key, NO otherwise.

See also:	− toManyRelationshipKeys, − toOneRelationshipKeys

ownsDestinationObjectsForRelationshipKey:

− (BOOL)ownsDestinationObjectsForRelationshipKey:(NSString *)key

Returns YES if the receiver has a relationship identified by key that owns its destination, NO otherwise. If an object owns the destination for a relationship, then when that destination object is removed from the relationship, it’s automatically deleted. Ownership of a relationship thus contrasts with a delete rule, in that the first applies when the destination is removed and the second applies when the source is deleted.

See also:	− deleteRuleForRelationshipKey:, − ownsDestinationObjectsForRelationshipKey: (EOClassDescription), − ownsDestination (EORelationship)

propagateDeleteWithEditingContext:

− (void)propagateDeleteWithEditingContext:(EOEditingContext *)anEditingContext

Sends a propagateDeleteForObject:editingContext: message to the receiver’s EOClassDescription. This causes the destination objects of the receiver’s relationships to be deleted according to the delete rule for each relationship:

Delete Rule	Action

EODeleteRuleNullify	The destination object is simply removed from the relationship,

and the receiver is likewise removed from the destination’s

reciprocal relationship if there is one.

EODeleteRuleCascade	As above, but the destination object is also deleted and

sent a propagateDeleteWithEditingContext: message.

EODeleteRuleDeny	Applied in validateForDelete, not in this method.

See also:	− deleteRuleForRelationshipKey:

removeObject:fromBothSidesOfRelationshipWithKey:

− (void)removeObject:(id)anObject fromBothSidesOfRelationshipWithKey:(NSString *)key

Removes anObject from the receiver’s relationship identified by key, and also removes the receiver from anObject’s reciprocal relationship if there is one. For a to-one relationship, anObject is removed using takeValue:forKey: with nil as the value. For a to-many relationship, anObject is removed using removeObject:fromPropertyWithKey:.

See also:	− addObject:toBothSidesOfRelationshipWithKey:

removeObject:fromPropertyWithKey:

− (void)removeObject:(id)anObject fromPropertyWithKey:(NSString *)key

Removes anObject from the receiver’s to-many relationship identified by key, without modifying any reciprocal relationship. Similar to takeValue:forKey:, this method first attempts to invoke a method of the form removeFromKey:. If the receiver doesn’t have such a method, this method gets the property array using valueForKey: and operates directly on that.

If the array is mutable, this method simply locates anObject and removes it using removeObjectAtIndex:. Otherwise it constructs a new array containing any existing objects minus anObject, then sets it using takeValue:forKey:.

See also:	− addObject:toPropertyWithKey:, − removeObject:fromBothSidesOfRelationshipWithKey:

snapshot

− (NSDictionary *)snapshot

Returns an NSDictionary whose keys are those of the receiver’s attributes, to-one relationships, and to-many relationships, and whose values are the values of those properties, with EONull substituted for nil. For to-many relationships, the dictionary contains shallow copies of the arrays to preserve the ids of the contents.

See also:	− updateFromSnapshot:, − allPropertyKeys, − valueForKey:

takeValue:forKey:

− (void)takeValue:(id)value forKey:(NSString *)key

Sets the value for the property identified by key to value. NSObject’s implementation does so by first checking the receiver for a selector of the form setKey:, invoking it if there is one. If there’s no such method, and accessInstanceVariablesDirectly returns YES, NSObject’s implementation checks for an instance variable named key and sets the value directly, autoreleasing the old value and retaining the new one.

If there’s neither an accessor method nor an instance variable matching key, NSObject’s implementation invokes handleTakeValue:forUnboundKey: as a fallback mechanism. Subclasses can override handleTakeValue:forUnboundKey: to handle the request in some other way.

See also:	− takeValue:forKeyPath:, − takeValuesFromDictionary:, − valueForKey:

takeValue:forKeyPath:

− (void)takeValue:(id)value forKeyPath:(NSString *)keyPath

Sets the value for the derived property identified by keyPath to value. A key path has the form relationship.property (with one or more relationships); for example “department.name”. NSObject’s implementation of this method gets the destination object for each relationship using valueForKey:, and sends the final object a takeValue:forKey: message with value and property.

See also:	− takeValuesFromDictionary:, − valueForKeyPath:

takeValuesFromDictionary:

− (void)takeValuesFromDictionary:(NSDictionary *)aDictionary

Sets properties of the receiver with values from aDictionary, using their keys to identify the properties. NSObject’s implementation invokes takeValue:forKey: for each key-value pair, substituting nil for EONull values in aDictionary.

See also:	− updateFromSnapshot:, − takeValue:forKeyPath:, − valuesForKeys:

toManyRelationshipKeys

− (NSArray *)toManyRelationshipKeys

Returns the names of the receiver’s to-many relationships, as determined from the EOClassDescription. You might wish to override this method to add keys for relationships not defined by the EOClassDescription. The access layer’s subclass of EOClassDescription, EOEntityClassDescription, returns the names of to-many relationships designated as class properties.

See also:	− toOneRelationshipKeys., − attributeKeys, − attributeKeys, − toManyRelationshipKeys (EOClassDescription)

toOneRelationshipKeys

− (NSArray *)toOneRelationshipKeys

Returns the names of the receiver’s to-one relationships, as determined from the EOClassDescription. You might wish to override this method to add keys for relationships not defined by the EOClassDescription. The access layer’s subclass of EOClassDescription, EOEntityClassDescription, returns the names of to-one relationships designated as class properties.

See also:	− toManyRelationshipKeys., − attributeKeys, − attributeKeys, − toOneRelationshipKeys (EOClassDescription)

unableToSetNilForKey:

− (void)unableToSetNilForKey:(NSString *)key

Invoked from takeValue:forKey: when it’s given a nil value for a scalar property (such as an int or a float). NSObject’s implementation raises an NSInvalidArgumentException. Subclasses can override it to handle the request in some other way, such as by substituting zero or a sentinel value and invoking takeValue:forKey: again.

updateFromSnapshot:

− (void)updateFromSnapshot:(NSDictionary *)aSnapshot

Takes the values from aSnapshot, setting each one according to its key using takeValue:forKey:. In the process, EONull values are converted to nil, and array values are set as shallow mutable copies to preserve the ids of the contents.

See also:	− takeValuesFromDictionary:, − snapshot

validateForDelete

− (NSException *)validateForDelete

Confirms that the receiver can be deleted in its current state, returning nil if it can or an NSException that the sender may raise if it can’t. For example, an object can’t be deleted if it has a relationship with a delete rule of EODeleteRuleDeny and that relationship has a destination object.

NSObject’s implementation sends the receiver’s EOClassDescription a validateObjectForDelete: message (which performs basic checking based on the presence or absence of values). Subclasses should invoke super’s implementation before performing their own validation, and should combine any exception returned by super’s implementation with their own:

- (NSException *)validateForDelete

{

    NSException *exception = [super validateForDelete];

    if (/* some other violation */ ) {

        NSException *newException = /* the extra exception */;

        exception = [NSException aggregateExceptionWithExceptions:[NSArray

             arrayWithObjects:exception, newException, nil]];

    }

    return exception;

}

See also:	− validateForInsert, − validateForSave, − validateForUpdate, − validateValue:forKey:, + validationExceptionWithFormat: (NSException Additions)

validateForInsert

− (NSException *)validateForInsert

Confirms that the receiver can be inserted in its current state, returning nil if it can or an NSException that can be raised if it can’t. NSObject’s implementation simply invokes validateForSave.

See also:	− validateForDelete, − validateForSave, − validateForUpdate, − validateValue:forKey:, + validationExceptionWithFormat: (NSException Additions)

validateForSave

− (NSException *)validateForSave

Confirms that the receiver can be saved in its current state, returning nil if it can or an NSException that the sender may raise if it can’t. NSObject’s implementation sends the receiver’s EOClassDescription a validateObjectForSave: message, then iterates through all of the receiver’s properties, invoking validateValue:forKey: for each one. If this results in more than one exception, the exception returned contains the additional ones in its userInfo dictionary under the EOAdditionalExceptions key. Subclasses should invoke super’s implementation before performing their own validation, and should combine any exception returned by super’s implementation with their own:

- (NSException *)validateForSave

{

    NSException *exception = [super validateForSave];

    if (/* some other violation */ ) {

        NSException *newException = /* the extra exception */;

        exception = [NSException aggregateExceptionWithExceptions:[NSArray

             arrayWithObjects:exception, newException, nil]];

    }

    return exception;

}

Enterprise objects can implement this method to check that certain relations between properties hold; for example, that the end date of a vacation period follows the begin date. To validate an individual property, you can simply implement a method for it as described under validateValue:forKey:.

See also:	− validateForDelete, − validateForInsert, − validateForUpdate, + validationExceptionWithFormat: (NSException Additions), + aggregateExceptionWithExceptions: (NSException Additions)

validateForUpdate

− (NSException *)validateForUpdate

Confirms that the receiver can be updated in its current state, returning nil if it can or an NSException that the sender may raise if it can’t. NSObject’s implementation simply invokes validateForSave.

See also:	− validateForDelete, − validateForInsert, − validateForSave, − validateValue:forKey:, + validationExceptionWithFormat: (NSException Additions)

validateValue:forKey:

− (NSException *)validateValue:(id *)valuePointer forKey:(NSString *)key

Confirms that the value referenced by valuePointer is legal for the receiver, returning nil if it can or an EOValidationException that the sender may raise if it can’t. NSObject’s implementation sends a validateValue:forKey: message to the receiver’s EOClassDescription. If that message doesn’t return an exception, it checks for a method of the form validateKey: (for example, validateBudget: for a key of “budget”) and invokes it, returning the result.

Enterprise objects can implement individual validateKey: methods to check limits, test for nonsense values, and otherwise confirm individual properties. To validate multiple properties based on relations among them, override the appropriate validateFor... method.

See also:	− validateForDelete, − validateForInsert, − validateForSave, − validateForUpdate, + validationExceptionWithFormat: (NSException Additions)

valueForKey:

− (id)valueForKey:(NSString *)key

Returns the value for the property identified by key. NSObject’s implementation does so by first checking the receiver for a method named key, invoking it if there is one. If there’s no such method, and accessInstanceVariablesDirectly returns YES, NSObject’s implementation checks for an instance variable named key and returns the instance variable.

If there’s neither an accessor method nor an instance variable matching key, NSObject’s implementation invokes handleQueryWithUnboundKey: as a fallback mechanism. Subclasses can override handleQueryWithUnboundKey: to handle the request in some other way.

See also:	− valueForKeyPath:, − valuesForKeys:, − takeValue:forKey:

valueForKeyPath:

− (id)valueForKeyPath:(NSString *)keyPath

Returns the value for the derived property identified by keyPath. A key path has the form relationship.property (with one or more relationships); for example “department.name”. NSObject’s implementation of this method gets the destination object for each relationship using valueForKey:, and returns the result of a valueForKey: message to the final object.

See also:	− valuesForKeys:, − takeValue:forKeyPath:

valuesForKeys:

− (NSDictionary *)valuesForKeys:(NSArray *)keys

Returns an NSDictionary containing the property values identified by each of keys. NSObject’s implementation invokes valueForKey: for each key in keys, substituting EONull in the NSDictionary for returned nil values.

See also:	− valueForKeyPath:, − takeValuesFromDictionary:

willChange

− (void)willChange

Notifies any observers that the receiver’s state is about to change, by sending each an objectWillChange: message. See the EOObserverCenter class specification for more information.


Value Class Additions (NSObject)

Copyright ©1996 by NeXT Software, Inc.  All Rights Reserved.

Inherits From:	none (NSObject is a root class)

Declared In:	EOControl/EOQualifier.h

EOControl/EOSortOrdering.h

Class Description

Enterprise Objects Framework adds several methods to NSObject for comparing values. Though declared for NSObject, most of these methods work properly only with value classes: NSString, NSDate, NSNumber, NSDecimalNumber, and EONull. These methods are used for sorting and for evaluating qualifiers in memory.

Method Types

Sorting value objects	− compareAscending:

− compareCaseInsensitiveAscending:

− compareCaseInsensitiveDescending:

− compareDescending:

Testing value objects	− doesContain:

− isEqualTo:

− isGreaterThan:

− isGreaterThanOrEqualTo:

− isLessThan:

− isLessThanOrEqualTo:

− isLike:

− isNotEqualTo:

Instance Methods

compareAscending:

− (NSComparisonResult)compareAscending:(id)anObject

Returns NSOrderedAscending if anObject is naturally ordered after the receiver, NSOrderedDescending if it’s naturally ordered before the receiver, and NSOrderedSame if they’re equivalent for ordering purposes. NSObject’s implementation of this method simply invokes compare:.

See also:	− compareDescending:, − compareCaseInsensitiveAscending:, − compareCaseInsensitiveDescending:

compareCaseInsensitiveAscending:

− (NSComparisonResult)compareCaseInsensitiveAscending:(id)anObject

Returns NSOrderedAscending if anObject is naturally ordered—ignoring case—after the receiver, NSOrderedDescending if it’s naturally ordered before the receiver, and NSOrderedSame if they’re equivalent for ordering purposes. NSObject’s implementation of this method invokes compare:, while NSString’s invokes caseInsensitiveCompare:.

See also:	− compareCaseInsensitiveDescending:, − compareAscending:, − compareDescending:

  compareCaseInsensitiveDescending:

− (NSComparisonResult)compareCaseInsensitiveDescending:(id)anObject

Returns NSOrderedAscending if anObject is naturally ordered—ignoring case—before the receiver, NSOrderedDescending if it’s naturally ordered after the receiver, and NSOrderedSame if they’re equivalent for ordering purposes. NSObject’s implementation of this method invokes compare: and inverts the result, while NSString’s invokes caseInsensitiveCompare: and inverts the result.

See also:	− compareCaseInsensitiveAscending:, − compareDescending:, − compareAscending:

compareDescending:

− (NSComparisonResult)compareDescending:(id)anObject

Returns NSOrderedAscending if anObject is naturally ordered before the receiver, NSOrderedDescending if it’s naturally ordered after the receiver, and NSOrderedSame if they’re equivalent for ordering purposes. NSObject’s implementation of this method simply invokes compare: and inverts the result.

See also:	− compareAscending:, − compareCaseInsensitiveDescending:, − compareCaseInsensitiveAscending:

doesContain:

− (BOOL)doesContain:(id)anObject

Returns YES if the receiver contains anObject, NO if it doesn’t. NSObject’s implementation of this method returns YES only if the receiver is a kind of NSArray and contains anObject. In all other cases it returns NO. This method is used in the Framework only by EOQualifier for in-memory evaluation.

isEqualTo:

− (BOOL)isEqualTo:(id)anObject

Invokes isEqual: and returns the result. This method is used in the Framework only by EOQualifier for in-memory evaluation.

See also:	− doesContain:, − isGreaterThan:, − isGreaterThanOrEqualTo:, − isLessThan:, − isLessThanOrEqualTo:, − isLike:,− isNotEqualTo:

isGreaterThan:

− (BOOL)isGreaterThan:(id)anObject

Invokes compare: and returns YES if the result is NSOrderedDescending. This method is used in the Framework only by EOQualifier for in-memory evaluation.

See also:	− doesContain:, − isEqualTo:, − isGreaterThanOrEqualTo:, − isLessThan:, − isLessThanOrEqualTo:, − isLike:,− isNotEqualTo:

isGreaterThanOrEqualTo:

− (BOOL)isGreaterThanOrEqualTo:(id)anObject

Invokes compare: and returns YES if the result is NSOrderedDescending or NSOrderedSame. This method is used in the Framework only by EOQualifier for in-memory evaluation.

See also:	− doesContain:, − isEqualTo:, − isGreaterThan:, − isLessThan:, − isLessThanOrEqualTo:, − isLike:,− isNotEqualTo:

isLessThan:

− (BOOL)isLessThan:(id)anObject

Invokes compare: and returns YES if the result is NSOrderedAscending. This method is used in the Framework only by EOQualifier for in-memory evaluation.

See also:	− doesContain:, − isEqualTo:, − isGreaterThan:, − isGreaterThanOrEqualTo:, − isLessThanOrEqualTo:, − isLike:,− isNotEqualTo:

isLessThanOrEqualTo:

− (BOOL)isLessThanOrEqualTo:(id)anObject

Invokes compare: and returns YES if the result is NSOrderedAscending or NSOrderedSame. This method is used in the Framework only by EOQualifier for in-memory evaluation.

See also:	− doesContain:, − isEqualTo:, − isGreaterThan:, − isGreaterThanOrEqualTo:, − isLessThan:, − isLike:,− isNotEqualTo:

isLike:

− (BOOL)isLike:(NSString *)aString

Returns YES if the receiver matches aString according to the semantics of the SQL like comparison operator, NO if it doesn’t. See “Using Wildcards” in the EOQualifier class specification for the wildcard characters allowed. NSObject’s implementation returns NO; NSString’s performs a proper comparison. This method is used in the Framework only by EOQualifier for in-memory evaluation.

See also:	− doesContain:, − isEqualTo:, − isGreaterThan:, − isGreaterThanOrEqualTo:, − isLessThan:, − isLessThanOrEqualTo:,− isNotEqualTo:

isNotEqualTo:

− (BOOL)isNotEqualTo:(id)anObject

Invokes isEqual:, inverts the result, and returns it. This method is used in the Framework only by EOQualifier for in-memory evaluation.

See also:	− doesContain:, − isEqualTo:, − isGreaterThan:, − isGreaterThanOrEqualTo:, − isLessThan:, − isLessThanOrEqualTo:, − isLike: