I just tried what is either a rather cool and elegant solution to a
problem, or a complete hack that only works by pure chance, and I'm
trying to decide which of these I have on my hands. Basically, I have a
few different objects, of different types, that want to perform some
action at regular intervals. They may not all need to be performing
these tasks at the same time - that is, they may not need to receive any
notification from a timer. Also, they will probably be using different
intervals - some things might want to be activated every tenth of a
second, others may not need to do any thing for 10 seconds. To implement
this functionality, I made a new Tickler class with Timer as super to it
and a Tickled class interface with a Tickle method. Now anyone that
wants to be updated just needs to implement Tickled->Tickle and create a
new Tickler. However, in my implementation, the Tickler references the
Tickled and the Tickled references the Tickler, creating a circular
reference which can lead to a memory leak. This isn't too big a deal at
the moment as all the objects are essentially permanent, and if I really
need to toss them I can just break the circular reference.
Now that I have that, I wanted to create a new, temporary object that
would live for a limited time frame, but perform some actions during
it's life. Say I want it to do something every second, and I want it to
do it 10 times. Well, using the Tickler there is a cool way of
accomplishing this - just make the object, which implements the Tickled
interface and return. So long as the circular reference exists, the
object will live, which means I don't need a property to track it. I can
start it up in one routine and immediately exit. Then, in the Tickle
method of the object, I just set its reference to the Tickler to be nil.
This breaks the circular reference, allowing both the Tickler and the
Tickled to be deleted. This is kind of interesting, as it lets me create
objects with a life of their own - I don't need to track them, they
simply live until their task is complete and die when they are finished,
independent of their creator.
So, my question is, is this safe? I am worried because the reference
count of the Tickler becomes 0 from a call the Tickler is making. So the
stack is:
1: RB Timer magic
2: Tickler.Action
3: Tickled.Tickle
when the object that caused 2: to run reaches 0. When is Tickler
actually released? When its refcount hits 0? When new memory is
allocated? And does RB know not to delete an object which is involved
with the current call-chain? I suppose I could have the Tickler break
the circle instead, after the call to the Tickled, but I need to have
some way of communicating that from the Tickled, which is the object
that knows when the task is complete...
--Brady
The La Jolla Underground
|