Storyboard, firing "enterScene" event twice when using "fade" effect. New Composer Class?

+1 … I’m getting this issue too.  Definitely seems like a bug with Corona - the show “did” and “will” are both individually being called twice.

@joe528, do you have a workaround you’re using for this?

@Rob, is there any way we can track the progress of bug reports, or formally +1 them?

Thanks,

Ed

Unfortunately I can’t change the visibility into the bug tracker.  And we don’t have a +1 system.

Rob

@edmoyse

For me, this bug happens when you go to other scene before the current scene "did’ show.

Therefore, my workaround for this is to add a flag, set it to true after the current scene “did” show.

Before this flag becomes true, do not go to any other scene (mostly, inside a touch listener, returns immediately if this flag is false).

+1. Sounds like this is related to this other thread:

http://forums.coronalabs.com/topic/45329-corona-transitionto-fires-oncomplete-twice/

Here is a simple test case. Let it run for a little while and it will crash. Just paste this to the main.lua and run it. No need for any other files. I have several apps that I can’t update before this is fixed so any workaround/help is appreciated!

local function FloatRight(\_object) local function FloatLeft() \_object.transition1 = transition.to(\_object, {time=4000, delta=true, x=\_object.contentWidth\*(-1), onComplete=FloatRight}) end \_object.transition1 = transition.to(\_object, {time=4000, delta=true, x=\_object.contentWidth, onComplete=FloatLeft}) end local function FloatUp (\_object) local function RemoveMe() if \_object.transition1 ~= nil then transition.cancel(\_object.transition1) end if \_object.transition2 ~= nil then transition.cancel(\_object.transition2) end display.remove(\_object) \_object = nil end \_object.transition2 = transition.to(\_object, {time = math.random(2500,5000), y = -100, onComplete = RemoveMe}) end local function CreateBubble() local bubble = display.newCircle(math.random(1,1024),810,math.random(4,40)) FloatRight(bubble) FloatUp(bubble) end timer.performWithDelay(11,CreateBubble,0)

@ploygonblog

(1) Why is your sample code related to this forum topic (“enterScene” fired twice)? or related to “OnComplete” fired twice?

(2) In your code, I have tested it and it does crash, however I don’t think it has anything to do with Corona.

Since your sample is large (you created a lot of bubbles), you created a rare race condition:

1 -> In RemoveMe(), you remove _object by calling display.remove(_object)

2 -> Before the system knows you already remove this object, OnComplete is still called sometimes (The race condition happens because you are not expecting this)

3 -> so in FloatLeft(),  _object.contentWidth is causing the crash (_object is already removed & niled)

To fix this problem, you can add this line right before display.remove(_object)

\_object.removed = true

And in FloatLeft(), check if this flag is set to true, if yes, just returns. (You can print something first, and you can see it’s actually happening now and then)

I have tested it, no more crash.

Thanks joe528 for your input, I appreciate it!

(1) Let me start by saying that the code is stable in old version of Corona( Graphics 1). The code crashes even though I cancel the transition (FloatLeft/FloatRight) before removing the object. This leads me to believe that it might be related to either transition.cancel or onComplete. But I cannot be sure.

I understand your workaround, but why, as you said “OnComplete is still called sometimes” ? I do cancel the transition before removing the object. How exactly could the onComplete still fire?

That’s why I said it’s due to “race condition”: http://en.wikipedia.org/wiki/Race_condition (Take a look at the Software section)

I think there are multiple threads running in the background and you cannot expect things to run in the order you are expecting. You said “You do cancel the transition before removing the object”, but your code is not “sequential” at all. 

In your sample code, transition cancellation is about to be called in Thread 1 and at the same time, onComplete is going to be called in Thread 2, who’s first? and how does CPU handle task switching? How could you be sure everything is executed in Thread 1 before switching to Thread 2?

Anyway, it’s a typical race condition problem. You just have to deal with it in a better way. For example, to use “State Machine” mechanism is even better. I don’t really like the workaround I gave you because I am not 100% sure if it will work for all the environments (because I am not sure how each CPU switches tasks).

By the way, the problem is that you were assuming everything in a block/function will all be executed before switching to other block/function. So instead of implementing state machine, you can add “Critical Section” idea on your sample, it should work too. 

But I am not sure if Lua has this critical section or mutex thing.

Thank you joe528 for elaborating! I think I’m starting understand the “race condition” concept.

  1. Why it works perfectly in older (G1) versions of Corona? I never had these problems in any of my apps before, but now with G2 I have these kinds of problems in several apps. Was “race condition” not possible in G1?

  2. In my tests your workaround seems 100% solid. However, if it is a “race condition”, I would assume it wouldn’t be 100% solid even with your workaround. I mean what if Thread1 is executing _object.removed = true at the same time as Thread2 is executing if _object.removed == true ?

(1) I think the underlying implementations are different in G1 & in G2. When you call transition.cancel or object.remove, you don’t know what have been executed in the middleware. Maybe firing onComplete takes few lines of code in G2 or maybe the mechanism to maintain the transitions has changed, so in your particular way of design, the race condition happens.

(2) They wouldn’t execute “at the same time”, just the order cannot be expected. Hence,

  1. If setting flag goes first, checking will fail, crash is avoided.

  2. If checking goes first, checking will succeed, here comes the tricky part, what if now CPU switching to Thread 2 & execute _object.remove instead of calling _object.contentWidth first? or maybe in this kind of case, it never switches task but execute the next line after a if statement? (And most function calls are not atomic instructions, so switching task might happen inside the middle of a function call)

so maybe putting “_object.removed = true” in the beginning of RemoveMe() is better. And you can also use timer.performWithDelay to call _object.remove() - a very small delay should be enough, maybe 5ms.

I am totally guessing :slight_smile: I don’t have solid evidence because I don’t really know the underlying implementation, but you just have to do something to avoid the race condition, hence the crash.

Thank you joe528 for taking the time to help! The code snippet seems perfectly stable now. But still this whole thing worries me a lot. I have programmed a dozen games with Corona and I have never experienced or heard of any crashes. Now with G2, several of my apps are unstable. All problems at least related to transitions. If the problem is the fact that with G2 I can produce “race condition” issues that were not possible with G1, I strongly feel that this should be documented in detail (and with examples) in the migration guide.

I wish that Corona staff would take a stance on this. How to make sure my code is 100% race condition free these days?

(sorry guys, I didn’t mean to hijack this thread. I genuinely believed my crash was related. At least the other thread I linked to, is related to onComplete)

I believe the storyboard firing twice bug is related to the transition library, not directly in Storyboard.  The bug I believe is still pending since in many cases there is a work around available.   Regardless, we will not be making repairs to Storyboard any more as we have deprecated it in favor of Composer (though I think this is an issue with Composer as well, since both libraries are using transitions.)

As far as how to eliminate race conditions, the community can provide you as high quality advice as we can.  Race conditions are not unique to Corona SDK, its a problem in any multi-tasking, event driven system.

Rob

Thanks Rob! So you agree my code snippet crashes because of a race condition and not because of any transition bug? It doesn’t crash with G1.

I have not analyzed your code.  This is not something we normally do as part of forum support.  It’s something you can use our paid support feature for.

I know that there is a reported bug about onComplete firing twice that seems related to this.  However, if you have introduced a race condition into your code and you can solve it, then that’s the best course of action as it’s something you can resolve faster than we can get this bug solved.

Rob

I believe the storyboard firing twice bug is related to the transition library, not directly in Storyboard.  The bug I believe is still pending since in many cases there is a work around available.   Regardless, we will not be making repairs to Storyboard any more as we have deprecated it in favor of Composer (though I think this is an issue with Composer as well, since both libraries are using transitions.)

Composer also has a similar bug. The “did show” event fires twice as I have reported.