Ludicrous Software

Passing Parameters in timer.performWithDelay()

Somebody on the Corona forums asked if it were possible to pass arguments to a timer callback from within the performWithDelay call. After a bit of thought, here’s what I came up with.

What they wanted was something like this:

1
2
3
4
5
function restartLevel(boolVal, stringVal)
  print("boolVal", boolVal)
  print("stringVal", stringVal)
end
timer.performWithDelay( 1000, restartLevel( true, "resetScore"))

Ignore syntactical issues for the moment as I’m copying their pseudo-code directly; also, I have no idea what their restartLevel function looks like, so I just made one up.

My first thought was that the simplest approach would be to just use a closure, so the code would look something like this:

1
2
3
4
5
6
7
8
9
10
function restartLevel(boolVal, stringVal)
  print("boolVal", boolVal)
  print("stringVal", stringVal)
end

local function doIt()
  restartLevel(true, "resetScore")
end

timer.performWithDelay( 1000, doIt)

This will work nicely, but if you have to do this a lot, then you’ll end up with closures all over the place. That in itself isn’t a bad thing, since Lua is so closure-friendly, but it means having to write all those closures, which is more work for you. And since there are a lot of cool things you could be doing that don’t involve writing a bunch of repetitive code, here’s a way to avoid all of that:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
timer.oldPerformWithDelay = timer.performWithDelay

timer.performWithDelay = function(interval, func, ...)
  local iterations, params
  local options = {...}
  if type(options[1]) == "number" then
      iterations = options[1]
      params = options[2]
  else
      iterations = 1
      params = options[1]
  end
  local function doIt()
      func(params)
  end
  timer.oldPerformWithDelay(interval, doIt, iterations)
end

local function restartLevel(params)
  print("boolVal", params.boolVal)
  print("stringVal", params.stringVal)
end

timer.performWithDelay(1000, restartLevel, {boolVal = true, stringVal = "yo"})
timer.performWithDelay(1500, restartLevel, 5, {boolVal = false, stringVal = "iterations!"})

All I’ve done is move the closure, which is called doIt, into the new timer.performWithDelay function. doIt calls the function passed to performWithDelay, along with whatever parameters have been provided.

Because the original timer.performWithDelay accepts an optional third argument (the number of iterations), the new function needs to account for that. To do this, the new function checks to see if the third value passed to it is a number. If it is, then it’s assumed that this is the number of iterations, and the fourth value is the table of parameters to pass along. If the third value is not a number, then plan for a single iteration, and assign the third value passed to the new function to the parameters to be passed on. You can see the iterations in action in the second performWithDelay call.