Previous Book Contents Book Index Next

Inside Macintosh: Programmer's Guide to MacApp / Part 1 - MacApp Theory and Architecture
Chapter 3 - Core Technologies


A stream is, literally, a stream of bytes that can flow from one location to another. Streams can be used for many purposes:

Streaming in MacApp depends on two features:

The TStream class is an abstract class that contains methods for reading and writing many primitive data types, such as bytes, integers, characters, points, rectangles, and strings. When an application calls one of these methods, passing data of the appropriate type, the method transfers the data with a call to ReadBytes or WriteBytes.

In the TStream class, the ReadBytes and WriteBytes methods are unimplemented and are left as a responsibility of the subclass. The following subclasses of TStream implement ReadBytes and WriteBytes to read and write data for specific destinations:

The TCountingStream class counts the bytes in a stream without writing them to a real destination; it is not used for reading.
The TDragFlavorStream class calls Drag Manager routines to read and write flavor data.
This subclass of TResourceStream reads from or writes to a resource handle. TFileResourceStream has an associated file and uses it to set the current resource file before reading or writing.
The TFileStream class reads from or writes to a file.
The THandleStream class reads from or writes to a memory handle.
The TResourceStream class reads from or writes to a resource handle.
The TSectionStream class reads and writes data for a section (sections are described in "Publish and Subscribe," beginning on page 184).

Streaming Object Data

Persistent data is the data needed to recreate an object in the same state as when it wrote its data. For example, to recreate a view with its previous size and location, the persistent data must include the size and location. But if the view is always re-created with a default size and location, its persistent data need not include size and location.

When you override the WriteTo method to stream the data for a class, you generally need to write only its persistent data, because any constant data can be initialized automatically. When you override the ReadFrom method to read the data for a class from a stream, you read only the data you wrote in the WriteTo method, in exactly the same order.

TStream includes the ReadStreamObject and WriteStreamObject methods for reading and writing an entire object. Classes that support the use of ReadStreamObject and WriteStreamObject (including all of MacApp's view classes) override the GetStandardSignature method to supply a unique signature ID. For example, MacApp defines the following signature ID to be returned by the GetStandardSignature method of the TButton class:

const IDType kStdButton = 'butn';
Objects are streamed using the following mechanisms to ensure efficiency:

Examples of Using Streams in MacApp

You can find useful examples of how to use the different types of streams in the MacApp class library. For example:

This class uses a drag flavor stream in its GetDataAsHandle and GetDataStream methods.
This class uses a counting stream in its DoNeedDiskSpace method to determine how much space the file will take on disk. Your document subclasses can use a similar approach. It also uses a file stream in its DoReadScript and DoWriteScript methods, to read a script from a file or write one to a file.
This class uses a section stream in its DoRead and DoWrite methods, to read or write section data.
This class creates a handle stream in its DoMakeViewStream method. The view server's ReadViewsFromResource and WriteViewsToHandle methods call on DoMakeViewStream to supply a stream.
For additional information on using streams in your application, see
Chapter 27, "Working With Streams."

Advantages of Using Streams

One great benefit of using streams is that if your classes know how to read and write their data for one kind of stream, they can read and write for any kind of stream. If you create ReadFrom and WriteTo methods, your application's classes will be able to read and write their data to document files, memory handles, and other destinations. They will also be able to use a counting stream to count bytes and determine how much storage is needed.

Another advantage of using streams is that you can associate a failure handler with a stream operation, which gives you explicit control when an error occurs during the reading and writing of documents or other destinations.

Disadvantages of Using Streams

Although MacApp's stream classes can serve many purposes, they do have inherent limitations. If any of these limitations represents a serious problem for your application, make sure your design includes an adequate solution before using streams.

File Formats

Using the stream mechanism to write a document can result in a file format that varies widely from document to document and is difficult to explain. The data for a document is written out by the object hierarchy that exists at the time the document is written, and it can be read in conveniently only by recreating that same set of objects.

MacApp writes a length word with each object, so it is possible to skip over objects your application doesn't understand. However, information in a skipped object is effectively lost to your application and may prevent the recreation of a meaningful document.

Because a file format based on an object hierarchy can vary from document to document, it is difficult to support backward compatibility across document versions. For example, if you create a new version of your application that uses new or modified objects, it may be difficult to ensure that the new objects can read data written by the old ones.

One solution is to write a unique tag with each object, and change the tag if the object format changes in a future version of the application. With some effort, a tagged format can be built on top of MacApp's implementation of streams.

Speed and Data Access

MacApp's stream classes provide basic persistent object support, but they are not an object database. If you need to create files with large numbers of objects, and especially if you want random read/write access to objects, you can use MacApp's streams to pack objects into handy chunks, but you will need to use some other software to access the chunks on disk. Third-party products are available for this purpose.

Ease of Modification

The class hierarchy of MacApp's stream classes can make it difficult to modify stream behavior across all classes without changing MacApp code. For example, if you want to add a feature that works for all stream classes, you have to either modify TStream itself in the MacApp code or create a separate subclass for TFileStream, THandleStream, and each of the other stream classes.

One way to work around this is to create your own subclass of TStream, such as TSuperStream, and give it a field TStream * fStream that references a stream object of any type. You can set the fStream field by passing a stream to the ISuperStream method.

TSuperStream can override the ReadBytes and WriteBytes methods of TStream and make them defer to the fStream field. For example, ReadBytes would call fStream->ReadBytes. (You may need to override other methods as well, such as GetPosition and SetPosition.) Now you can add a feature to TSuperStream and use it with any stream type.

Previous Book Contents Book Index Next

© Apple Computer, Inc.
25 JUL 1996