Destroying MIAWs

Be careful with MIAW's destroying themselves - it will cause random crashes (especially under windows) if the forget command occurs in a handler originating in the MIAW (presumably because Director tries to finish the handler and return to the MIAW after its been removed from memory). Simply having the MIAW tell the stage to execute another handler which forgets the MIAW isn't enough since the original handler in the MIAW still hasn't completed before the forget occurs. The way to avoid these errors is to defer using the actual forget command until after the MIAW handler which started the process has completed. In pseudo code, we want to do this:

on originalHandlerInMiaw

  tell the stage to forget (the activeWindow) after thisHandler finishes


A common approach to safely forgetting a MIAW is to have the MIAW set a flag (a global variable) which the stage checks every exit frame (or some similar event) which will only occur after the MIAW's original handler has completely finished. If the stage notices that the flag has been set, it forgets the MIAW.

The disadvantage of this approach is that the MIAW is relying on the stage to have the correct global variable and handlers monitoring this variable. The ideal approach would be to have all the code necessary to properly destroy the MIAW stored in the MIAW itself (whilst still ensuring that the handler which triggers the MIAWs destruction has completed before the forget command actually occurs).

This can be achieved using a timeout object and a script object instantiated with the sole purpose of destroying the MIAW. With this technique, the MIAW creates a script object from a script member in its own cast (once the script object is instantiated, it exists independently of the script member that originally made it - hence the object can safely destoy the miaw since the originating handler is not 'in' the MIAW). This script object (the 'DestroyMIAW' object) then tells the stage to create a timeout object which has the 'DestroyMIAW' object as its callback target.

After the original MIAW handler has finished, the timeout object then makes a callback to the DestroyMIAW object which then forgets the MIAW.

-- Parent Script "DestroyMIAW" (stored in the MIAW)

-- A generic script for to destroy MIAWs. 

property myMIAW

on new (me, aWindowref)

  myMIAW = aWindowref

  -- Note: tell the stage to create the timeout (otherwise it 

  -- will go into the timeoutlist of the MIAW.

  tell the stage to tmp = timeout(me.string).new(1, #TimeOutCallback, me)


on TimeOutCallback (me, aTimer)

  myMIAW.forget() -- destroy the MIAW

  aTimer.forget() -- destroy the timeout


--   Note that its not really necessary to explicitly VOID the MIAW reference

-- here since the property will be released when the "DestroyMIAW" object 

-- is destroyed anyway. 

Notice that the "DestroyMIAW" parent script doesn't return a reference to itself. You shouldn't ever need to keep a reference to an object created from this script. This object will be kept alive by the reference the timeout object keeps. When the timeout makes the callback, the 'DestroyMIAW' object also destroys the timeout object. And since the timout object held the only reference to the 'DestroyMIAW' object, it is itself destroyed.

To use this parent script in your MIAW, you could include an on closeWindow handler (or a mouseUp handler on a button) like this:

on closeWindow

  script("Destroy MIAW").new(the activeWindow)


Related issues:

To properly destroy a MIAW, you need to remove all persistent references to the MIAW. When a MIAW is created, a reference is automatically placed in the windowList. The forget() command removes the MIAW from this list. However, if (for some reason) you have created additional references (such as storing a reference to the MIAW in a global variable), then you must also remove these other references before the MIAW will be destroyed. The Forget() command will not check each and every variable in a movie to see if it contains a reference to the MIAW.

First published 16/12/2005