Update view in while loop

Discussion in 'iOS Programming' started by larswik, Dec 1, 2012.

  1. larswik macrumors 68000

    Sep 8, 2006
    Last night, while learning new things, I started a little game from scratch. It is a simple ship that moves left and right via 2 UIButtons at the bottom of the screen and rocks that fall from the top that you avoid by shooting at them.

    Everything worked well using NSTimer and the screen updated and UIbuttons functioned. But the more objects that moved on screen the slower it ran. I read threads today about getting away from NSTimer and using while loops. But while my game loops no buttons work or the screen wont refresh. I can hear the sounds running and the collision sound when a rock hits the ship.

        [self addRock];
        while (game_is_running)
            [self runLoop];
        [self shipMove]; // Uses UIButtons to move left and right.
        [self moveShotPosition]; //Moves the shot int eh y direction
        [self moveRockPostion]; //moves the rock in the y direction down
        [self checkCollision]; // checks for collision of rock and ship or shot and rock
        if (!music.playing && lives > 0) { // If music stops, restart it.
            [music play];
       [self performSelectorOnMainThread:@selector(updateTheView) withObject:nil waitUntilDone:YES];
        [self.view setNeedsDisplay];
    I do understand that in the main thread, control is is transfered to the While loop and nothing else will work like buttons and screen redraw until control is released. I attempted to insert a [self performSelector.... waitUntilDone:YES] in the loop. After reading about this method it seems that it will break away from the while loop to perform a task and then return control again to the while loop. I have that line of code call a method that should update the screen [self.view setNeedDisplay];

    But nothing is updating and the screen it's frozen, what am I missing to break away from the while loop to update / redraw the screen with the new object positions?
  2. larswik thread starter macrumors 68000

    Sep 8, 2006
    I kept surfing and I discovered CADisplayLink.

    This seems to create a loop like NSTimer but is much faster and handles messages from UIButtons and screen updates. Working with NSRunLoop it seems to solve my problem. Not sure why, the docs are a little confusing and I am trying to wrap my head around it.
  3. xStep, Dec 1, 2012
    Last edited: Dec 1, 2012

    xStep macrumors 68000

    Jan 28, 2003
    Less lost in L.A.
    The performSelectorOnMainThread: isn't helping because all it is calling is setNeedsDisplay and immediately returning. The native event loop is being blocked by your runLoop. I expect the audio works because when you issue a call to play it, it gets pushed onto a background thread via what ever call you are using.

    Perhaps try running your runLoop on a background thread. You'd also place the while loop inside that method before calling it on a new thread from your appDidAppear.

    I'm no game programmer so others likely have a better solution or fuller answer. For instance, you may need to have some kind of synchronization code so that updating your frames doesn't occur while the system is drawing.

    Another thought is that perhaps your NSTimer had the same issue of running on the main thread and blocking updates. The more graphics you had, the longer it takes to update the information, perhaps several cycles of the event loop. Use of secondary thread might help.

    EDIT: Wow, CADisplayLink is a neat find.
  4. PhoneyDeveloper macrumors 68040


    Sep 2, 2008
    If you call selectorOnMainThread from the main thread it isn't going to do what you want.

    CADisplayLink has as its purpose this sort of thing.

    You might want to look at cocos2d.
  5. larswik thread starter macrumors 68000

    Sep 8, 2006
    Thanks guys, I like learning new things. This weekend was a good opportunity to try something different.

    About the CADisplayLink, I was wondering about the frame rate? The Doc's say this in the first part.... "A CADisplayLink object is a timer object that allows your application to synchronize its drawing to the refresh rate of the display."

    I am assuming that the speed of this is set by the refresh of the device you are using it on? So as phones get faster and faster it will not speed up, but maintain the same speed, or the refresh rate in hz, like 60hz or 60 frames per second. If phones someday reach 120hz then my game would run 2x as fast?

    This Class seems to solve my problems of the while loop I was having. But if I were to make a game for both Android and IOS then this would not work. I would need to use a while loop approach.

  6. ArtOfWarfare macrumors G3


    Nov 26, 2007
    My understanding is that a display link will make it so that your display code and screen refreshes are kept in sync. If your code runs quicker than the screen can refresh, your code will be slowed down. If the screen refreshes faster than your code runs, then the screen refreshes will be slowed down. This ensures that partial renders are never displayed, screen tears don't occur, and the graphics chips don't overheat (an issue that occured with StarCraft II on faster machines, for example. Some of the menus in the game simply used loops for displaying them, and the chips overheated trying to draw it millions of times a second when the screen couldn't even refresh that often.

    This is also useful for applications where you're running on multiple screens (IE, you're using AirPlay to display one thing on a TV screen but something else on your iOS screen.)

    I believe I've seen something about an Android display linker class in the API, but I've never needed it and can't remember the name of it off the top of my head.
  7. larswik thread starter macrumors 68000

    Sep 8, 2006
    That is a great explanation, I get that now. It is a really handy Class that simplifies a lot.

Share This Page