CHAPTER 1: Persistent Data and Data Conversion Persistent objects 13
An object is stored to the database only if it is changed, making the default object data invalid. A single
object could exist and be used in several user sessions without ever being written to the database. A
persistent object whose data is not stored in the database is constructed from the object’s constructor.
Whether it instantiates a new object or returns a reference to an object previously instantiated,
IDatabase::Instantiate increments the reference count on the object and returns an IPMUnknown* to the
requested interface, if the interface is available.
Using commands and wrappers
There are commands for creating new objects of many of the existing classes (for example,
kNewDocCmdBoss, kNewPageItemCmdBoss, kNewStoryCmdBoss, and kNewUIDCmdBoss). When you
need to create an object, first look for a suite interface, utility interface, or facade interface to make
creating your object safe and easy. If no such interface exists, use a command if one is available, rather
than creating the object with general functions.
Using a command to create an object protects the database. Commands are transaction based; if you use a
command when the application already is in an error state, the command performs a protective
shut-down, which quits the application rather than permitting a potentially corrupting change to be made
to the document. Commands also provide notification for changes to the model, allowing observers to be
updated when the change is made, including changes made with undo and redo operations.
When you implement a new type of persistent object, also implement a command to create objects of that
type, using methods outlined in “Implementing persistent objects” on page 14
.
Types of references to objects
There are four types of reference to a persistent object: UID, UIDRef, InterfacePtr, and UIDList. Each type of
reference serves a different purpose. Understanding these reference types makes working with persistent
objects easier.
UID is the type used for a unique identifier within the scope of a database. The UID value by itself is not
sufficient to identify the object outside the scope of the database. Like a record number, a UID value
has meaning only within a given database. UID values are useful for storing, passing, and otherwise
referring to boss objects, because UID values have no run-time dependencies, and there is an instance
cache ensuring fast access to the instantiated objects. kInvalidUID is a value used to identify a UID that
does not point at a valid object. Any time a UID is retrieved and needs to be tested to see if it points at
a valid object, the UID should be compared to kInvalidUID.
A UIDRef object contains two pieces of information: a pointer to a database and the UID of an object
within this database. A UIDRef is useful for referring to objects, because it identifies both the database
and the object. Using a UIDRef object is a common means of referring to a persistent object, especially
when the persistent object is to be passed around or stored, since a UIDRef does not require the
referenced object to be instantiated. A UIDRef object cannot itself be persistent data, because it has a
run-time dependency, the database pointer. An empty or invalid UIDRef object has kInvalidUID as its
UID and a nil pointer as its database pointer.
An InterfacePtr object contains a pointer to an interface (on any type of boss object) and identify an
instantiated object in main memory. While an InterfacePtr object on the boss is necessary for working
with the boss, it should not be used to track a reference to a persistent object, because this forces the
object to stay in memory. In many cases, a nil pointer returned from InterfacePtr does not indicate an
error state but simply means the requested interface does not exist on the specified boss.