2.2.1 Game Freezes on Launch in 3.0

Member
Posts: 61
Joined: 2009.01
Post: #1
Hey guys,

I've got a game that works fine with iPhone 2.2.1 but in 3.0 the screen stays at the loading image (Default.png) and never actually starts up. Tracing through the code, it appears to be looping through normally, but the start window never goes away. I'm think this is maybe because I start an un-ending while loop within applicationDidFinishLaunching, so some change in 3.0 tells the iPhone that my app never finished launching and therefore the start screen doesn't go away.

Let me put a few code snippets in here.
Code:
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
    // Initialize the random number seed.
    initRandomSeed(time(NULL));    
    
    // Set up the view and input controller
    vaic = [[ViewAndInputController alloc] init];

    //etc etc
    //All initializations finished.

    //Start the game loop.
    running = YES;
    [self mainLoop];
}

- (void) mainLoop
{
    //Lots of timer-related stuff using mach_timer.

    //Start the game loop.
    while (running)
    {
        NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

        //Do lots of gamey stuff.

        //Yield to system calls (touches, etc.) for one ms.
        while( CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.001, FALSE) == kCFRunLoopRunHandledSource);

        //Do some game draw-y stuff.

        [pool release];
    }
}

As I step through the code, the while loop is being executed normally (and continuously), and no exceptions are being thrown. The first screen still doesn't ever go away, however.

In 2.2.1, the CFRunLoopRunInMode call up there would allow the phone to think the app had finished launching and therefore run normally. It doesn't appear to be that way in 3.0, however.

Any ideas?

Thanks.
Moderator
Posts: 133
Joined: 2008.05
Post: #2
Honestly, I'm not sure what the infatuation with creating run loops is. Write your game first, optimize later. In this code, you already have a run loop. If you check out main.m, you'll see a call to UIApplicationMain(). This function creates a run loop and instantiates an instance of UIApplication. After the instance of UIApplication is created, your app delegate is sent the message applicationDidFinishLaunching:. When execution of applicationDidFinishLaunching: finishes executing, your application jumps in to the run loop created by UIApplicationMain().

Of course, applicationDidFinishLaunching: never returns. You enter an infinite loop immediately.

The lesson to learn here is: if you don't know what the run loop does, don't try and outdo it. Read the documentation*. Chances are, you aren't going to outdo it anyway.

* The documentation will tell you that the run loop begins and checks for any input. This input could be a touch, a timer, or any other source you can add to a run loop (like a CFStream callback). When one of those events occurs, execution breaks off in to one of your methods (like touchesBegan:, or that CFStream callback). When your methods finish, execution goes back to the run loop. The next step of the run loop checks all of your UIViews and redraws them if necessary. There isn't anything special or glamorous about the run loop. It's just an infinite loop doing those things.
Member
Posts: 61
Joined: 2009.01
Post: #3
I already did write my game. It was working fine in 2.2.1, like I said, then suddenly wouldn't work in 3.0. I was originally using NSTimer and it was giving me very unstable and unpredictable performance. I am used to writing my own run loops in order to get very fine control over what's happening (a common necessity for almost any game), and so I made one. If you use Apple's loop then it's pretty unpredictable and very blackboxed. Hence the reason to make your own. It's not an "infatuation," it's intelligent. I didn't do it until we had already been in development or 2 months, because we needed more control over the loop. So before you tell me I don't know what or why I'm doing it, perhaps ask.

That being said, my post above was only a guess as to why it wasn't working. It looks like I might be very wrong. So then what do you think the reason is? Any other ideas? Because your post really wasn't very helpful, you pretty much just said, "why did you make your own run loop." No conjectures on why I'm getting a hang at first.

Also, for a game, it doesn't make sense to have the game only do stuff on response to input. It needs to be running constantly. At least for any real-time game.

And I got the idea this might be the problem by reading this line from the 3.0 release notes:
Quote:Issue: Application is killed on launch.
Applications should not run blocking, potentially open-ended operations on the main thread. This leaves the application unresponsive to user input, and when done at startup or shutdown, the application is likely to be killed by the system.
Moderator
Posts: 133
Joined: 2008.05
Post: #4
No, my post said you are creating a loop in an already running loop. I also said that Apple's run loop will check for input and redraw views if necessary. If you block that process (for example, by jumping in to your own loop and not allowing the rest of Apple's run loop to execute), your views don't get redrawn. If your application appears to hang, its because your view is not getting redrawn.

Now, given what you've said and the code you've shown, you don't understand the run loop. You are trying to reinvent the wheel by adding square corners.

Now, for a game, that's right, it doesn't make sense to have the game only "do stuff" on response to input. It does need to be running constantly - and by running constantly, you mean the view should be constantly updating with the data it currently has. That data is the position of your objects, game state, etc. In fact, this is exactly what a timer does. You say "Hey run loop, you might be getting some touches, when you get one, you should change the data. In the mean time, just keep drawing when you can."

If you have a speed issue, there are other optimizations you can perform before you get in to trying to create your own run loop. Read the final responses to the post you made about Alternative to NSTimer, they are well written and from experienced devs.

All that being said, show some tact when people are trying to help you.
Sage
Posts: 1,232
Joined: 2002.10
Post: #5
Also, 3.0 is under NDA. You can't discuss it here.
Member
Posts: 61
Joined: 2009.01
Post: #6
longjumper Wrote:Now, for a game, that's right, it doesn't make sense to have the game only "do stuff" on response to input. It does need to be running constantly - and by running constantly, you mean the view should be constantly updating with the data it currently has. That data is the position of your objects, game state, etc. In fact, this is exactly what a timer does. You say "Hey run loop, you might be getting some touches, when you get one, you should change the data. In the mean time, just keep drawing when you can."

This is still making it sound like I can't say model.update(delta) unless the user has been creating input. Yes the views will keep drawing, but what they draw is not getting updated on its own, right?

longjumper Wrote:All that being said, show some tact when people are trying to help you.
True statement. Apologies.

arekkusu Wrote:Also, 3.0 is under NDA. You can't discuss it here.
I can't discuss it at all? I thought I couldn't discuss specific features, but it was okay to say "my app doesn't work in 3.0, any idea why?"
Moderator
Posts: 3,572
Joined: 2003.06
Post: #7
demonpants Wrote:I can't discuss it at all? I thought I couldn't discuss specific features, but it was okay to say "my app doesn't work in 3.0, any idea why?"

The whole NDA thing is a very touchy subject, and we take it seriously around here, so no, unfortunately, nothing at all about 3.0. Sorry. Sad
Member
Posts: 245
Joined: 2005.11
Post: #8
Quote:I can't discuss it at all? I thought I couldn't discuss specific features, but it was okay to say "my app doesn't work in 3.0, any idea why?"
But it isn't okay for anyone to answer...
Moderator
Posts: 133
Joined: 2008.05
Post: #9
demonpants Wrote:This is still making it sound like I can't say model.update(delta) unless the user has been creating input. Yes the views will keep drawing, but what they draw is not getting updated on its own, right?

You can do a model.update(delta) during the timer callback, and then redraw your scene. I think the confusion with all of this is what NSTimer really does. When you add a timer to the run loop, you are adding non-user input as an event to your run loop. That is, the magical pixies that live in your iPhone press a button every 1/60th of a second (or whatever your timer is set to do).

This timer seems like it should fire at exactly 1/60th of a second, but it does not. The timer is not an interrupt. It can't stop the execution of your application to execute its callback whenever it wants to. Consider the following pseudo code:

Code:
AddTimerWithIntervalToRunLoop(1.0 / 60.0);
do {
    if(AnyTouchesProducedAnEvent())
        respondToTouchEventsWithClientCode();
    
    float deltaTime = getTimeSinceLastLoopIteration();
    for(NSTimer *t in runLoopTimers) {
        AddDeltaTimeToTimer(deltaTime, t);
        if(TimerNeedsToFire(t)) {
            CallTimerCallback(t);
        }
    }
        
    for(UIView *v in visibleViews) {
        if(ViewNeedsToBeRedrawn(v)) {
            RedrawView(v);
        }
    }
}while(true);

AddDeltaTimeToTimer(float dt, NSTimer *t)
{
    t.elapsedTime += dt;
    if(t.elapsedTime > t.interval)
    {
        t.shouldFire = YES;
        t.elapsedTime -= t.interval;
    }    
}

This is more or less what the run loop is doing. As you can see, if you are currently in respondToTouchEvents(), execution is blocked until that function returns. Similarly, if you are in a timer callback, execution is blocked until you are done doing your timer stuff (drawing, updating sprites).

This means a couple of things:
1. Not only should your rendering code be ultra fast, so should your touch handling code. Time spent in either of these methods is time lost for the other one.
2. You'll have to compute the time it took since the last update for your delta time for your sprites, it's not guaranteed to be 1 / 60 seconds.

Because the run loop will only process one event per iteration (as per the documentation), it might be beneficial to redraw your scene at the end of a touch event.
Moderator
Posts: 613
Joined: 2004.09
Post: #10
I have closed this thread to new post regarding mention of iPhone 3.0. Please consult your NDA agreement for specific details about what is not allowed.

Kyle Richter
DragonForged.com
Twitter: @kylerichter
Thread Closed