EOEditingContext

From EOFWiki
Jump to: navigation, search

Contents

Design

EOEditingContext is a fairly complex class, but broken down into its conceptual piece it becomes easy to understand.

Configurations

The possible configurations of EOEditingContext are:

  • with or without NSUndoManager (Undo)
  • with or without a parent EOObjectStore (Fetching, faulting, saving)
  • within or outside of NSRunLoop (Delayed processing of edits)

The registration and edit tracking of objects is always available, regardless of configuration.

Registration and Edit tracking

An application can place newly created objects into an EOEditingContext by calling insertObject:.

   foo = [[Foo new] autorelease];
   [editingContext insertObject:foo];

This objects can be removed from the EOEditingContext by deleteObject:. Changes to an object in a EOEditingContext are noted by the EOEditingContext, if the object prior to setting a property to a new value, calls [self willChange]. Typically this is coded into the accessor.

- (void) setName:(NSString *) s
{
   [self willChange];
   [name autorelease];
   name = [s copy];
}

Objects can also be fetched or faulted from an EOObjectStore into an EOEditingContext. When fetching objects, typically from a database, the responsible EOObjectStore will use recordObject:forGlobalID: (and not insertObject:) to place these objects in the EOEditingContext. These objects can also be deleted via deleteObject: from the application.

EOEditingContextEditing.png

The EOEditingContext maintains a few lists to track the edit operations. The following diagram shows the state of the object after the operation has been performed on the EOEditingContext. For example after a fresh object is inserted into the EOEditingContext it will show up in the list of insertedObjects. After a saveChanges operation, the object is persisted. So the current state is as if it had just been fetched. It's registered in the EOEditingContext but it has no edits. The clear color indicates an object, that isn't tracked any longer by the EOEditingContext.

EOEditingContextObjectStates.png

Fetching, faulting, saving

If the EOEditingContext is configured to run with a parent EOObjectStore, and in 99.9% of all cases it is, it gains the ability to fetch, fault and save objects. These are the basic persistance mechanisms that EOObjectStore provides. What fetching and faulting in detail means is the scope of another article.

Undo

An EOEditingContext may or may not have an NSUndoManager. By default every EOEditingContext has one, but if you don't need undo capability it may be wise to remove it to conserve memory.

If an NSUndoManager is present, the EOEditingContext will generate appropriate undo information automatically to undo the edits made to the EOEnterpriseObject. To do that, the EOEditingContext takes snapshots from the edited object and stores the differences on the undo stack.

Delayed processing of edits

The EOEditingContext will use NSRunLoop features to schedule it's final processing of edits that accumulated during the runloop event. Specifically it will setup this delayed runloop handler on the first edit of the runloop cycle.

   [[[NSRunLoop currentRunLoop] performSelector:@selector( processRecentChanges)
                                         target:self
                                       argument:nil
                                          order:EOFlushEOEditingContextRunLoopOrdering
                                          modes:[[EODelayedObserverQueue defaultObserverQueue] runLoopModes]];

In programs, which do not use AppKit or otherwise to not use NSRunLoop, changes aren't processed automatically. These programs usually call processRecentChanges on their own, or use methods, which force the execution of processRecentChanges like saveChanges or insertedObjects.

Read MulleEOF and the NSRunLoop for a more detailed treatment.

Object archiving support

EOEditingContext has two class methods +initObject:withCoder: and encodeObject:withCoder: to provide an archiving facility outside of EOObjectStore. This method archives snapshots of the object graph using the NSCoding protocol. EOEnterpriseObjects can use this facility by implementing two methods:

@implementation Foo 

- (void) encodeWithCoder:(NSCoder *) coder 
{
   [EOEditingContext encodeObject:self 
                        withCoder:coder];
}

- (id) initWithCoder:(NSCoder *) coder 
{
   return( [EOEditingContext initObject:self 
                              withCoder:coder];
}
@end

In general one would like the decoded objects to reside in an EOEditingContext. Set the substitutionEditingContext before decoding:

   [EOEditingContext setSubstitutionEditingContext:myEditingContext];
   foo = [[Foo alloc] initWithCoder:someCoder];
   [EOEditingContext setSubstitutionEditingContext:nil];

If you set +setUsesContextRelativeEncoding:<tt> to YES, then EOEditingContext will try to minimize the archived snapshot data by archiving the EOGlobalID of the object instead and appropriate diffs.

Basic Principles

  • The EOEditingContext manages only objects, that adhere to the informal EOEnterpriseObject protocol
  • Any NSObject adheres to the informal EOEnterpriseObject protocol (but some overriden protocol methods are usually needed for anything but the most basic operations)
  • EOEnterpriseObjects belong to one and only one EOEditingContext
  • To edit an object from another EOObjectStore or EOEditingContext, this object must be fetched or faulted
  • As EOEditingContext only operates on EOEnterpriseObjects local to itself, changes to these objects do not become apparent to other EOEditingContexts or EOObjectStores until they are saved.

Threading (MulleEOF)

Methods on <tt>EOEditingContext that lock and therefore are thread safe are

  • - addEditor:
  • - deleteObject:
  • - deletedObjects
  • - faultForRawRow:entityNamed:
  • - hasChanges
  • - insertObject:
  • - insertedObjects
  • - invalidateAllObjects
  • - lockObject:
  • - locksObjectsBeforeFirstModification
  • - objectWillChange:
  • - objectsWithFetchSpecification:
  • - processRecentChanges
  • - refaultObjects
  • - registeredObjects
  • - removeEditor:
  • - revert
  • - saveChanges
  • - tryToSaveChanges
  • - updatedObjects

On these EOEditingContext "technical methods" a programmer has to do the locking itself:

  • - arrayFaultWithSourceGlobalID:relationshipName:editingContext:
  • - committedSnapshotForObject:
  • - currentEventSnapshotForObject:
  • - faultForGlobalID:editingContext:
  • - forgetObject:
  • - globalIDForObject:
  • - initializeObject:withGlobalID:editingContext:
  • - insertObject:withGlobalID:
  • - invalidateObjectsWithGlobalIDs:
  • - isObjectLockedWithGlobalID:editingContext:
  • - lockObjectWithGlobalID:editingContext:
  • - objectForGlobalID:
  • - objectsForSourceGlobalID:relationshipName:editingContext:
  • - objectsWithFetchSpecification:editingContext:
  • - recordObject:globalID:
  • - refaultObject:withGlobalID:editingContext:
  • - saveChangesInEditingContext:

The rest of the methods need not be concerned about thread safety.

Links

Personal tools