COPersistentRoot class documentation
COPersistentRoot : NSObject <COPersistentObjectContext>Overview
Considering all of the above parts together, a persistent root represents a document or a top-level object in a CoreObject store.
Conceptual Model
For each new persistent root, CoreObject produces a new UUID triplet based on:
- a persistent root
- a branch collection that results in a history graph describing all the changes made to a document (document has a very loose meaning here)
- a branch
- the persistent root initial branch
- a root object
- the document main object e.g. the top node of a structed document, a photo or contact object
The persistent root UUID and branch UUID are unique (never reused) accross all CoreObject stores, unless a persistent root has been replicated accross stores.
Generally speaking, CoreObject constructs (branches, revisions, objects, stores etc.) are not allowed to share the same UUID. For the replication case, constructs using the same UUID are considered to be identical (same type and data) but replicated. For now, replication support is restricted to collaborative editing (the synchronization protocol is discussed in COSynchronizerClient).
For each persistent root, the root object UUID is reused accross branches. For a persistent root cheap copy, the root object UUID of the parent persistent root is reused. As such, use -[COPersistentRoot UUID] to track top-level objects in the CoreObject store.
Common Use Cases
The most common use case would be accesssing the object graph through -objectGraphContext (if branches aren't being used by the application).
Attributes and Metadata
The -metadata property can be set to a JSON compatible NSDictionary to store arbitrary application metadata. This property is persistent, but not versioned (although metadata changes can will be undone/redone by COUndoTrack, if the commit that changes the metadata is recorded to an undo track).
Branches
Branches act similarly to git in that a branch is a movable pointer on to the history graph. See COBranch for more detail.
New persistent roots contains just a single branch (see -branches).
You can ignore the COBranch API and just use COPersistentRoot to access the object graph with -objectGraphContext .
-objectGraphContext represents a dynamically tracked current branch, that presents another content, every time -currentBranch is set to another branch.
Creation
Persistent roots are never instantiated directly, but can be created with -[COEditingContext insertNewPersistentRootWithRootObject:] or -[COEditingContext insertNewPersistentRootWithEntityName:] . A persistent root doesn't become persistent until it gets committed to the store.
You can access uncommitted persistent roots or recreate previously committed ones, through -[COEditingContext persistentRootForUUID:] or -[COEditingContext persistentRoots] .
Cheap Copies
Making a cheap copy of a persistent root creates a new persistent root (with a new UUID) and a single branch (also with a new UUID), however the current revision of the new branch will be set to the revision where the cheap copy was made. See -[COBranch makePersistentRootCopyFromRevision:] or -[COBranch makePersistentRootCopy] .
The copy is a true copy, in that it can have no observable effect on the source persistent root. However, the fact that it's a cheap copy will be evident in the interconnected history graphs.
Deletion
CoreObject uses an explicit deletion model for Persistent Roots, controlled by the -deleted flag. Modifying the flag marks the persistent root as having changes to commit. A persistent root with the -deleted flag set on disk is like a file in the trash. It can be undeleted by simply setting the -deleted flag to NO and committing that change.
Only when the deleted flag is set to YES (and committed), is it possible for CoreObject to irreversibly delete the underlying storage of the persistent root. Currently, the only way to do this is to call a lower level store API, however this functionality will probably be exposed in COEditingContext at some point.
Cross Persistent Root References
CoreObject supports to create references to other root objects accross persistent roots:
- unidirectional references to a specific branch (can be any branch including the current branch)
- bidirectional references accross two dynamically tracked current branches
For creating dynamically tracked references to a -currentBranch , -rootObject must be used as the object being referred from another persistent root. For bidirectional references, the relationship cache will ensure the consistency is maintained even in case the current branch is changed on either side.
For creating references to a specific branch, the root object being referred from another persistent root, can be any root object, except -[COPersistentRoot rootObject] . You would usually use -branches , -branchForUUID: or -currentBranch to get a specific branch, then access its root object.
Persistent Root Properties
- - (ETUUID *) UUID
The UUID that is bound to a single persistent root per CoreObject store.
Two persistent roots belonging to distinct CoreObject stores cannot use the same UUID unless they point to the same persistent root replicated accross stores.
For now, persistent root replication accross distinct CoreObject stores is used during collaborative editing (there is no public replication API though).
- - (NSDictionary *) metadata
The metadata in JSON format attached to the persistent root.
Any changes to the metadata is saved on the next persistent root commit.
You must never overwrite any existing metadata set by CoreObject.
- - (void) setMetadata: (NSDictionary *)metadata
The metadata in JSON format attached to the persistent root.
Any changes to the metadata is saved on the next persistent root commit.
You must never overwrite any existing metadata set by CoreObject.
- - (BOOL) deleted
The persistent root deletion status.
If the persistent root is marked as deleted, the deletion is committed to the store on the next editing context commit.
If set to YES for an uncommitted branch, the branch isn't staged for deletion, but immediately discarded. As a result, a deleted uncommitted branch cannot be undeleted.
TODO: Document the current branch deletion behavior (either on -currentBranch or in -branches for the current branch UUID). If supported, we should explain how a new current branch is picked.
- - (void) setDeleted: (BOOL)deleted
The persistent root deletion status.
If the persistent root is marked as deleted , the deletion is committed to the store on the next editing context commit.
If set to YES for an uncommitted branch, the branch isn't staged for deletion, but immediately discarded. As a result, a deleted uncommitted branch cannot be undeleted.
TODO: Document the current branch deletion behavior (either on -currentBranch or in -branches for the current branch UUID). If supported, we should explain how a new current branch is picked.
- - (NSDate *) modificationDate
The newest head revision date among all branches.
Changing a branch current revision doesn't alter the returned date. See -[COBranch currentRevision] .
See -[COBranch headRevision] and -[CORevision date] .
- - (NSDate *) creationDate
The first revision date.
The first revision is the same accross all branches in a persistent root.
See -[COBranch firstRevision] and -[CORevision date] .
- - (COPersistentRoot *) parentPersistentRoot
The persistent root this is a copy of, or nil if the receiver is not a copy.
See -[COPersistentRoot isCopy] .
- - (BOOL) isCopy
Returns YES if this persistent root is a copy (-parentPersistentRoot != nil).
See -[COBranch isCopy] .
- - (NSDictionary *) attributes
Returns attributes of the persistent root as reported by the store.
See COPersistentRootAttributeExportSize, COPersistentRootAttributeUsedSize.
- - (NSString *) name
The user-facing name of the persistent root. This property is provided for convenience; it is implemented on top of the metadata property.
Because it's stored in the metadata dictionary, changes to the name are visible across all revisions and branches.
You could also store a document name in the root object's -name property (see -[COObject name] ), which would have the expected consequences: changing the name would cause a new revision to be committed, old revisions would still use the old name, and different branches could have different names for the document.
TODO: Rename to -displayName or -label to emphasize that this is the user-facing name?
- - (void) setName: (NSString *)name
The user-facing name of the persistent root. This property is provided for convenience; it is implemented on top of the metadata property.
Because it's stored in the metadata dictionary, changes to the name are visible across all revisions and branches.
You could also store a document name in the root object's -name property (see -[COObject name] ), which would have the expected consequences: changing the name would cause a new revision to be committed, old revisions would still use the old name, and different branches could have different names for the document.
TODO: Rename to -displayName or -label to emphasize that this is the user-facing name?
Accessing Branches
- - (COBranch *) currentBranch
The branch that opens when double-clicking a persistent root to edit it.
Also used to resolve inter-persistent root references to this persistent root when no explicit branch is provided.
Changing this value stages it for commit; upon the next persistent root commit, the change is saved to disk and replicated to other applications.
TODO: Document the deletion behavior for [[self currentBranch] setDeleted: YES].
- - (void) setCurrentBranch: (COBranch *)currentBranch
The branch that opens when double-clicking a persistent root to edit it.
Also used to resolve inter-persistent root references to this persistent root when no explicit branch is provided.
Changing this value stages it for commit; upon the next persistent root commit, the change is saved to disk and replicated to other applications.
TODO: Document the deletion behavior for [[self currentBranch] setDeleted: YES].
- - (NSSet *) branches
All the branches owned by the persistent root (excluding those that are marked as deleted on disk), plus those pending insertion and undeletion (and minus those pending deletion).
The returned branches never contains the -currentBranch object, but contains another current branch instance (both instances use the same UUID).
- - (NSSet *) deletedBranches
All the branches marked as deleted on disk, excluding those that are pending undeletion, plus those pending deletion.
TODO: Document if the current branch UUID can appear among the returned branches.
- - (COBranch *) branchForUUID: (ETUUID *)aUUID
Returns the branch using the given UUID or nil.
The persistent root retains the returned branch.
This method can return the same branches than -branches and -deletedBranches (including those pending deletion and undeletion), but the loading is restricted to the requested branch.
For the current branch UUID, never returns the -currentBranch object, but a distinct current branch instance (both instances use the same UUID).
See also -setDeleted: .
Editing Context Nesting
- - (COEditingContext *) parentContext
The editing context managing the receiver.
The parent context makes possible to edit multiple persistent roots simultaneously and provide an aggregate view on the editing underway.
COPersistentRoot objects are instantiated and released by the parent context.
The parent context is managed by the user.
- - (COEditingContext *) editingContext
Pending Changes
- - (BOOL) hasChanges
Returns whether the persistent root contains uncommitted changes.
Branch insertions, deletions, undeletions, and modifications (e.g. editing branch metadata, reverting branch to a past revision) all count as uncommitted changes.
See also -discardAllChanges and -[COBranch hasChanges] .
- - (void) discardAllChanges
Discards the uncommitted changes to reset the branch to its last commit state.
Branch insertions, deletions, undeletions and modifications (e.g. editing branch metadata, reverting branch to a past revision) will be cancelled.
All uncommitted inner object edits in the object graphs owned by the branches will be cancelled.
-branchesPendingInsertion , -branchesPendingDeletion , -branchesPendingUndeletion and -branchesPendingUpdate will all return empty sets once the changes have been discarded.
See also -hasChanges and -[COBranch discardAllChanges] .
Convenience
- - (id) rootObject
Shorthand for [[self objectGraphContext] rootObject] .
You can use this root object to create a cross persistent reference that dynamically tracks the current branch. If the receiver's current branch is changed, this object is updated in-place to reflect the new current branch. By extension, if there are cross-persistent root references in other persistent roots to this root object, the branch switch is immediately visible through those references.
If you use [[self currentBranch] rootObject] or [otherBranch rootObject], the cross persistent root reference in another persistent root will track a specific branch. For example, even if the current branch changes in the receiver, the other persistent root will continue to refer to the root object of the previous current branch.
- - (void) setRootObject: (id)rootObject
Shorthand for [[self objectGraphContext] rootObject ] .
You can use this root object to create a cross persistent reference that dynamically tracks the current branch. If the receiver's current branch is changed, this object is updated in-place to reflect the new current branch. By extension, if there are cross-persistent root references in other persistent roots to this root object, the branch switch is immediately visible through those references.
If you use [[self currentBranch] rootObject] or [otherBranch rootObject], the cross persistent root reference in another persistent root will track a specific branch. For example, even if the current branch changes in the receiver, the other persistent root will continue to refer to the root object of the previous current branch.
- - (COObject *) loadedObjectForUUID: (ETUUID *)uuid
Shorthand for [[self objectGraphContext] loadedObjectForUUID:] .
- - (CORevision *) currentRevision
Shortcut for [[self currentBranch] currentRevision] .
For a new persistent root, the revision is nil, unless it is a cheap copy. See -[COBranch makeCopyFromRevision:] .
- - (void) setCurrentRevision: (CORevision *)currentRevision
Shortcut for [[self currentBranch] currentRevision ] .
For a new persistent root, the revision is nil, unless it is a cheap copy. See -[COBranch makeCopyFromRevision:] .
- - (CORevision *) headRevision
Shortcut for [[self currentBranch] headRevision].
- - (void) setHeadRevision: (CORevision *)headRevision
Shortcut for [[self currentBranch] headRevision] .
- - (COObjectGraphContext *) objectGraphContext
Returns the object graph that dynamically tracks the -currentBranch .
This object graph context is not the same than [[self currentBranch] objectGraphContext] , although its content is the same (their item graphs are equal). For the same inner object UUID, both use distinct inner object instances.
When -setCurrentBranch: is called, this object graph content changes. It is updated with -[COObjectGraphContext setItemGraph:] , to present the same content than [[self currentBranch] objectGraphContext].
This object graph context and [[self currentBranch] objectGraphContext] are kept in sync at commit time. There is a one-way update, so both are not allowed to contain changes, otherwise an assertion occurs at commit time. If -objectGraphContext or [[self currentBranch] objectGraphContext] contains some changes, a commit must be done, to start making changes to its counterpart.
See also -allObjectGraphContexts and -rootObject (for cross persistent root references).
- - (NSSet *) allObjectGraphContexts
This method is only exposed to be used internally by CoreObject.
Returns the object graphs for the -branches (if they have been instantiated), plus the object graph that dynamically tracks the -currentBranch (see -objectGraphContext).
Committing Changes
- - (BOOL) commitWithIdentifier: (NSString *)aCommitDescriptorId metadata: (NSDictionary *)additionalMetadata undoTrack: (COUndoTrack *)undoTrack error: (COError **)anError
Commits this persistent root changes to the store, bound to a commit descriptor identifier along the additional metadatas, and returns whether it succeeds.
See -[COEditingContext commitWithIdentifier:metadata:undoTrack:error:] .
- - (BOOL) commit
Commits this persistent root changes to the store and returns whether it succeeds.
You should avoid using this method in release code, it is mainly useful for debugging and quick development.
See -commitWithIdentifier:metadata:undoTrack:error:.
Previewing Old Revision
- - (COObjectGraphContext *) objectGraphContextForPreviewingRevision: (CORevision *)aRevision
Returns a read-only object graph context of the contents of a revision.
Tentative API...
Description
- - (NSString *) detailedDescription
Returns a multi-line description including informations about the branches, deletion status, attached metadata and pending changes.