However, there may be cases where references are kept not in variables, but in lists or the properties of other objects. As discussed in section 12.8, if a circular reference arises (if, for example, your object keeps a reference to itself -- not as outlandish as it may seem, honest guv -- or keeps a reference to another object which in turn keeps a reference to it, etc), the memory occupied by an object may be lost to your movie permanently.
If your objects are simple, and don't cross-reference one another, it should usually be sufficient to clear out any object variables that you're no longer using. If they're kept as globals, they'll stay around until you set them to something else, or issue a clearGlobals command. If they're kept in a local variable, then they'll vanish in a puff of unsmoke as soon as the particular handler they're in exits.
However, if you (like me) sometimes find yourself using objects that contain lists of other objects which in turn contain other lists and yet more objects, any one of which may in turn refer back to the first, you'll need to institute some way of aggressively clearing them up. Here's an extravagantly over-the-top way:
-- a generalized, recursive object/list disposal handler
-- note that in most cases you'll actually want to provide
-- a more specialized mKill (or whatever) method for each of
-- your objects that takes into account ownership issues
-- (ie, it only disposes of those parts of the object that
-- the object actually controls itself, and will leave alone
-- things that are merely references to objects under the
-- control of some other program entity; such considerations
-- are a matter of policy and can't be determined by a general
-- procedure such as this)
-- in addition, an mKill method would only need concern itself
-- with the specifics whereas this goes overboard trying to
-- handle anything that's slung at it
-- the hierarchy argument is used by the recursive call, and
-- should be left out when the handler is first called
-- ie, usage is:
-- dispose object
on dispose anObject, hierarchy
-- non-objects don't need to be disposed
-- (lists are objects as far as objectP() is concerned)
if not objectP(anObject) then return
-- we don't need to dispose of points and rects
if ilk(anObject, #point) or ilk(anObject, #rect) then return
-- use a string to determine wayward object types
set objStr = string(anObject)
-- we don't need to dispose of casts either
if word 1 of objStr = "(cast" then return
-- windows can be disposed easily
if word 1 of objStr = "(window" then
close anObject
forget anObject
return
end if
-- xobjects likewise
if char 2 to 7 of objStr = "Object" then
anObject(mDispose)
return
end if
-- I *think* that should've weeded out all stray object types
-- but just to be on the safe side...
if not listP(anObject) and word 1 of objStr <> "<offspring" and Â
word 1 of objStr <> "script" then return
-- check to see if we've already disposed this object
-- in our travels, and if not add it to the list of
-- those we've encountered so that we don't try to dispose
-- it again (this is mainly to avoid an infinite loop if
-- we've got a circular structure)
if not listP(hierarchy) then set hierarchy = []
if getOne(hierarchy, anObject) then return
add hierarchy, anObject
-- we have to treat lists and propLists differently from
-- objects and scripts because we can't delete
-- properties from an object
if listP(anObject) and not ilk(anObject, #propList) then
-- recursively dispose of all the objects and then
-- remove the reference to them from the list
repeat while count(anObject)
dispose getAt(anObject, 1), hierarchy
deleteAt anObject, 1
end repeat
return
end if
-- with propLists, there's the possibility that the property
-- may also be an object reference (no, really...)
if listP(anObject) then
-- recursively dispose of all the objects and
-- remove the references to them from the list
repeat while count(anObject)
set theProp = getPropAt(anObject, 1)
dispose getAt(anObject, 1), hierarchy
deleteAt anObject, 1
dispose theProp, hierarchy
end repeat
return
end if
-- with scripts and their offspring, we can only clear the
-- properties, we can't remove them, but that's sufficient
if not count(anObject) then return
repeat with index = 1 to count(anObject)
set theProp = getAProp(anObject, getPropAt(anObject, index))
dispose theProp, hierarchy
setProp anObject, getPropAt(anObject, index), 0
end repeat
end dispose
The above handler should be able to annihilate more or less any object
submitted to it, but it is wildly excessive. Disposing of every element of
every list and every property of every object is *very* slow and the high
level of recursion can also make it a terrible memory hog. Even for
circular references, it should usually be sufficient to use more slimline
disposal procedures like these:
-- snappier disposal
-- this is for lists only
on vaporize aList
repeat while count(aList)
deleteAt aList, 1
end repeat
end vaporize
and this is for script/child objects
on exterminate anObject
if count(anObject) = 0 then return
repeat with index = 1 to count(anObject)
setProp anObject, getPropAt(anObject, index), 0
end repeat
end exterminate
This is particularly effective if used in combination with custom mKill methods for your objects -- since you'll generally know where the dangerous bits of any object are, you can handle those more thoroughly and then just wipe the properties wholesale.
Factory objects are a little different. These have to be explicitly disposed of using the built-in mDispose method:
someObject(mDispose)If you forget to do this, the memory used by your object won't get reclaimed. If you reset the variable that tells you where it is, you won't be able to get the memory back without quitting Director or doing a wholesale purge. So, if you do use factory objects for some reason, take care to dispose of them properly.