ACS Patterns suite

Introduction

The Apple Class Suites (ACS) provides a collection of useful abstractions in the Patterns suite. Most of the Patterns suite is devoted to the event dispatching and idle time mechanism developed for the Network suite. Other features include buffer management and iteration, a dependency mechanism*, a class registration mechanism*, a simple error handling mechanism, and a number of other useful classes (described below under "Other Classes").

*formerly in MacApp, and not discussed here


Event and Idle Time Subsystem

Overview

The event and idle time subsystem, including the event senders and receivers and the events themselves, relies heavily on reference counting. The key requirement of reference counting is that if you want to keep an object around that has a reference count (is subclassed from MRefCountable_AC), you need to keep a CRefCountingPtr_AC pointing to it. Otherwise, the object may be deleted when you interact with the subsystem for event posting, event receiving, and idling. Reference counting allows the ownership of many different objects to be shared and it allows deletion to be handled in a more automatic manner.

When working with reference-counted objects, you should be careful to avoid the situation where two or more objects end up holding reference counts to each other, so that they are never deleted. The TidyHeap suite (a debugging tool that keeps track of blocks of memory allocated by new or deleted by delete) is handy for tracking down these types of problems. For additional information on reference counting, see the Auto Pointers release notes document.

The event and idle time dispatching mechanisms are flexible and generalized for use in any context. Developers can use the system in any way they wish. An event sender can be anything that need to notify x number of other objects that "something has happened". Event receivers are objects that need to respond to these changes in the state of the sender. These systems were developed in the context of the Network suite, but were designed to be flexible and not at all dependent on the Network suite.

Events are sent through the CReactor_AC class, which acts as an event dispatcher. Events are sent to and from objects that mix in in the MEventTransceiver_AC class. Objects receiving events explicitly register for events with objects that send events. Registration information is stored in an object of type CReactor_AC. Objects that send events don't know about the objects receiving events, and object receiving events only know about objects that send events long enough to register with them. Event receivers can receive events from any number of event senders. Arbitrary deletion orders are supported, so that events are always guaranteed to be dispatched to valid receivers from valid senders.

Idle time is handled by mixing in the class MIdler_AC. Idle time is dispatched to MIdler_AC objects from an instance of the CIdleTimeDispenser_AC class, which receives idle time from a subclass of an object instantiated from the CIdleTimeEngine_AC class. MEventTransceiver_AC is a subclass of MIdler_AC, and CReactor_AC is a subclass of CIdleTimeDispenser_AC.


Classes

CEvent_AC

This is the base class for all events. It mixes in MRefCountable_AC and therefore has a reference count. It also stores an event ID and an error value associated with the event. The event ID is an OSType value, such as 'null'. The Consume method allows CEvent_AC to "consume" an event, which means the event won't be propagated to any further event handlers. The file PatternEvents_AC.h defines several event ID constants, including kNullEvent and kTimedOut.

CEventWithData_AC

This is a templated subclass of CEvent_AC whose purpose is to store any type of associated data along with the event. The data can be another object, a pointer to an object, or a raw data type such as a long. CEventWithData_AC.h provides functions for creating events with data and extracting event data. Other useful functions, such as GetLongData, can be found in the CEvent API.

MIdler_AC

MIdler_AC is a reference-counted class that has a virtual Idle method. To get idle time, you call the GetIdleTimeFrom method to attach the MIdler to a CIdleTimeDispenser_AC (described next).

CIdleTimeDispenser_AC

The CIdleTimeDispenser_AC class simply dispenses idle time to a list of "attached" MIdler_AC objects. Each time CIdleTimeDispenser_AC::Idle is called, it makes one call to the Idle method of each attached MIdler object. CIdleTimeDispenser_AC's Idle method is called by a CIdleTimeEngine_AC object, and the idle time dispenser must be supplied with a pointer to the engine object.

CIdleTimeDispenser_AC mixes in MIdler, so it can receive idle time and is reference counted.

CIdleTimeEngine_AC

Think of the CIdleTimeEngine_AC class as providing the thread of execution, except that there is no dependency on threads at all. Simply subclass CIdleTimeEngine_AC, supply it as a reference to a CIdleTimeDispenser, and you can supply idling to any object that needs it. The Thread suite provides a pre-made ThreadedIdleEngine.

MEventTransceiver_AC

This mixin class is the workhorse of the event subsystem. It both sends and receives events. It mixes in MIdler_AC so it can receive idle time and is reference counted.

The two most important methods of MEventTransceiver_AC are PostEvent and ReceiveEvent. PostEvent takes a pointer to an event (remember that CEvent_AC is reference counted). Generally, you create the event and send it and the event subsystem deletes it. ReceiveEvent receives a pointer to a CEvent_AC and a pointer to the MEventTransceiver_AC that sent the event.

Example:
CEventWithData_AC<long> *ev = 
	new CEventWithData_AC<long>(eventID, errorVal, longValue);
eventSender->PostEvent(ev);

To send events, an MEventTransceiver_AC object needs a pointer to a valid CReactor_AC (described next). In most cases, a default CReactor_AC will be created if one isn't provided.

To receive an event, an MEventTransceiver_AC object needs to register for events from another CEventTransceiver_AC. Events are sent to the receiving MEventTransceiver_AC through the sending CEventTransceiver's CReactor_AC.

Example:
CFoo* myEventSender = new CFoo;
CBar* myEventReceiver = new CBar;
myEventReceiver->RegisterForEventsFrom(myEventSender);
myEventSender->PostEvent( new CEvent_AC( kTestID ));

CReactor_AC

CReactor_AC does the actual work of sending an event from one MEventTransceiver_AC object to another. An MEventTransceiver_AC object only gets events from those MEventTransceiver_AC objects it has registered with. The CReactor_AC keeps track of those registrations. When an event is posted to the CReactor_AC (the MEventTransceiver_AC::PostEvent method calls its fReactor's PostEvent method), the CReactor checks its list of sender/receiver pairs for receivers registered for events from the sending object. If you want the CReactor_AC to ignore the event sender, you can call SetDoFilter(false). Then all MEventReceivers will receive the event no matter who sent it.

CReactor_AC is a subclass of CIdleTimeDispenser_AC, so it can dispense idle time and is reference counted.

CAbstractTask_AC

CAbstractTask_AC, which mixes in MEventTransceiver, is basically a fancy version of MIdler_AC. It performs an action, repeatedly if necessary. You override the DoTask method to perform the action. Several options are adjustable, including the delay before DoTask is called and how frequently DoTask is called.

CAbstractTimer_AC

CAbstractTimer_AC is a subclass of CAbstractTask_AC whose purpose is to perform timing. Several options are adjustable, including how long to time something and what event, if any, to send. You override the HandleTimerEvent method to make your own timer.

CEventTransceiverTimer_AC

CEventTransceiverTimer_AC is a subclass a CAbstractTimer_AC. It's purpose is to send a timed-out event to a specific MEventTransceiver_AC which has registered for events from the timer. You call the SetEventTransceiver method to specify which object will receive the timed-out event.

CTemplatedTimer_AC

This is a templated class for timing any object. The only stipulation is that the object must define a DoHandleTimeEvent method.

CReactorFactory_AC

This class creates a CReactor_AC object. Override CreateReactor. Also, there is a default reactor factory, so that you can create a Reactor using the default Reactor factory, which is accessible via several static methods, such as CreateDefaultReactor.

CDefaultReactorFactory_AC

This is the CReactor_AC created by the default CReactorFactory_AC. It doesn't have a CIdleEngine_AC attached to it.

The Threads suite creates and installs a default factory that creates CReactor_AC objects with a ThreadedIdleEngine_AC, so all of the idle time is automagically threaded.

MEventReceiver_AC

This is a mixin class for simply receiving events. It is important to note that this class is not reference counted so it is safe to mix it in to classes which are not part of the ACS hierarchy, such as your application class. An MEventReceiver_AC object uses a CEventAdaptor_AC object to convert the event from an MEventTransceiver_AC event. MEventReceiver_AC automatically creates a CEventAdaptor_AC object for you if you don't specify one.

You register for events in the same way you do with MEventTransceiver_AC, by calling the RegisterForEventsFrom method, which in turn calls the same method of the CEventAdaptor_AC object (described next).

CEventAdaptor_AC

This class mixes in MEventTransceiver_AC. CEventAdaptor_AC has a list of MEventReceivers to whom it forwards all events it receives.

MEventRouter_AC

This class mixes in MEventTransceiver_AC. Its purpose is to reside invisibly between an event sender and receiver. That is, it doesn't change the semantics of the event. The idea is that you can subclass MEventRouter_AC and have it perform actions based on the events it receives before it forwards the event onto the receiving MEventTransceiver.

CTCPMultipleConnectionManager_AC provides a good example of how to use MEventRouter_AC. When a CTCPMultipleConnectionManager_AC object receives an event such as kConnectSucceeded, it gets a pointer of the CTCPConnection_AC from the event and stores it in a list. The connection manager then forwards the event to the receiving MEventTransceiver_AC object, which can do something very simple, such as put up a dialog alerting the user. The event transceiver doesn't have to manage the connection object itself.

 


Other Classes

CBuffer_AC

This reference-counted class provides a mechanism for easily managing a dynamically-sized buffer. Features include: automatic creation of buffer; management of unowned buffer; and dynamic sizing of owned buffer. The method GetIterator returns a CByteIterator_AC pointing to the data managed by the CBuffer_AC.

CByteIterator_AC

This class provides iteration over a raw buffer of bytes. It is designed to interoperate easily with CBuffer_AC. If built with debugging on, all operations provide assertion range checks.

CByteFilter_AC

CByteFilter_AC is a simple base class provided for data filtering operations. It is currently used by the Streams suite.

MErrorHandler_AC

This is a mixin class that responds to errors. Override the RespondToError method to handle the error. Parameters are an error and a pointer to the MErrorProne_AC object that caused the error.

MErrorProne_AC

This object is a base class for objects that have a lot of errors. If you assign a MErrorHandler_AC object to the MErrorProne_AC object, when MErrorProne_AC::ErrorOccured is called, the MErrorHandler_AC object will get first crack at handling the error.

CPair_AC

This templated class stores two objects as data members. The two objects can be anything. This class is suitable for use within lists and other collections.

CProperty_AC

This class is basically a wrapper for a bool data type. You can use this class for a public data member and because it overrides the "()" (parenthesis) operator, you can access the data member as if it is a member function:

Example:
class CFoo
{
	public;
	CProperty_AC IsFoo;
};
 
CFoo foo;
foo.IsFoo(true);
if(foo.IsFoo())
	DoSomething();

CStateMachine_AC

This simple class keeps track of an explicit state variable. Methods are provided for setting and getting the state.