Using one onComplete with multiple functions

Just use a flag and have a way to reset if you need to repeat the sequence later.

local executedOnComplete = false local function finalOnComplete( event ) if( executedOnComplete ) then return end executedOnComplete = true print( 'I only want to call finalOnComplete once') end local function one( onComplete ) timer.performWithDelay( math.random(1000), onComplete ) end local function two( onComplete ) timer.performWithDelay( math.random(1000), onComplete ) end local function three( onComplete ) timer.performWithDelay( math.random(1000), onComplete ) end local function doTest() executedOnComplete = false one( finalOnComplete ) two( finalOnComplete ) three( finalOnComplete ) end

He covered that in the OP:

  > I guess I could set a boolean to denote whether the function was called or not but that would get messy.

@ron,

Ah, yes (head smack).  

http://github.com/roaminggamer/RG_FreeStuff/find/master

Well, I still think this is best, but one could do a little work to make this less messy:

-- This function uses a closure and scoping trick to make a self-disposing -- onComplete that is guaranteed to run only once. local function trick( work ) local obj = {} obj.executed = false function obj.onComplete( self, target ) if( self.executed ) then return end self.executed = true if(work) then work( target ) end end return obj end local function onComplete( object ) print(object.name .. " executed onComplete @ " .. system.getTimer()) end local red = display.newCircle( 10, 10, 10 ) red.name = "red" red:setFillColor( 1, 0, 0 ) local green = display.newCircle( 10, 30, 10 ) green.name = "green" green:setFillColor( 0, 1, 0 ) local blue = display.newCircle( 10, 50, 10 ) blue.name = "blue" blue:setFillColor( 0, 0, 1 ) -- Create a wrapper object to do the work: local proxy = trick( onComplete ) transition.to( red, { x = 200, time = math.random( 1000, 1500 ), onComplete = proxy } ) transition.to( green, { x = 200, time = math.random( 1000, 1500 ), onComplete = proxy } ) transition.to( blue, { x = 200, time = math.random( 1000, 1500 ), onComplete = proxy } ) proxy = nil

Her’s the way much easier solution.

 function final() print( 'all done') end function three() --// function 3 code goes here timer.performWithDelay( math.random(1000),final) end function two() --// function 2 code goes here timer.performWithDelay( math.random(1000),three) end function one() --// function 1 code goes here timer.performWithDelay( math.random(1000),two) end one() --// starting the sequence

+1 for @ronburk’s closure abuse :smiley: :slight_smile: as some other approaches miss critical points in the OP ( non -sequential, on last complete, etc)

fwiw:  you could mix-and-match @ronburk’s semaphores with @roaminggamer’s object listener to create a semaphore “wrapper” (call it fe “partlyComplete”) around a self-contained counter and self-contained fn-reference (call it fe “trulyComplete”) – decrement the counter in self.timer(), calling self.trulyComplete when zero.  effectively same/similar as @ronburk’s, just using a table for the “storage” instead of upvalues. [EDIT:  oh nevermind, that IS what @ronburk did in his earlier example – that’s what I get for reading bottom-up :D]

Sigh, I sometimes miss key parts of posts, i.e. seeing the question I want to answer.

So hopefully the answers I gave didn’t confuse things too much.  At the very least it was an interesting discussion.

@roaminggamer. Unless I’m not seeing it correctly, it seems your trick( work ) approach would call onComplete on the first function execution rather than the last. (?)

@max.serduk. I’m not after a sequential function daisy-chain, the point was to determine which of several function calls completed last using the same onComplete callback.

So far I think ronburk’s abuse and closure hackery is the best.