Main Loop’s while programming on iOS devices in Objective-C…..

Loops on iOS devices to not tend to work very well, timers are also need not only for making games but for many programs. The main clearest and simplest options to is to use an NSTimer. These can be done as follows…

Declare the timer:

NSTimer *time = [NSTimer timerWithTimeInterval:0.1 target:(timeFunction:) selector:nil userInfo:nil repeats:YES;

The timerFunction called by the above command would look as follows:

-(void) timerFunction:(NSTimer *)timer
{
}

The above timer will of course execute 10 times a second and would work as a loop for the program you are trying to write. Two problems exist from using this type of loop. First Apple does not guarantee that the timer will fire when it is supposed to fire. Second since this is the case the UI will start to lag. For a modern high quality app that is required today this method will not work.

Another method would be to use a selector with a delay...

[preformSelector:@selector(timerFunction:) withObject:nil afterDelay:1];

The timerFunction would look as follows:

-(void)timerFunction
{
}

This method causes the exact same problems as a NSTimer. This can be very frustrating for developers. What is a usable solution…
I use CAAnimation to create my loop. How is this done. You should always be using CALayer anyways, if you do not know what these are, either look them up or I will do a post explaining them at a later date. Most program have a menu screen or an entry screen or a main program screen and that screen will have a background image. We can create that background image as a layer and run a loop on that layer.

Here is a source code for a test project that I wrote. This method overrides a couple of the CALayer methods and starts an animation loop that will call back through a delegate that will allow you to update your display without slowing down the program.

What methods do you need to override:

+(BOOL)needsDisplayForKey:(NSString *)key
{
    return [key isEqualToString:@"timerIndex"];
}

You need to override the needsDisplayForKey method so objective-c knows to call the display method when you want it to.

-(void)display
{
    unsigned int currentSampleIndex = ((MainViewBackGroundLayer *)[self presentationLayer]).timeIndex;
    if (didstart && currentSampleIndex == 1) {
        didstart = NO;
        [myDelegate updateDisplay];
    } else if (!didstart && currentSampleIndex != 1) {
        didstart = YES;
    }
}

You need to override the display method to change the display. I have a little check as shown above so you can slow this timer down.
The timer works very well for anything above 1/20th of a second, below that it does not really work. If you need to go faster than that for your display you have much bigger issues. If you want the timer to execute say every second you need the code I have in the display method.

The only other methods you will need are as follows:

-(id)initWithFile:(NSString *)fileName andFrame:(CGRect)frame
{
    if (self = [super init]) {
        NSString *imageString = [[NSString alloc] initWithFormat:@"%@",[[NSBundle mainBundle pathForResource:fileName ofType:@"png"]];
        UIImage *image = [[UIImage alloc] initWithContentsOfFile:imageString];
        self.contents = (id)image.CGImage;
        self.frame = frame;
        didstart = NO;
    }
    return self;
}
-(void)stopLoop
{
    [self removeAnimationForKey:@"timerAnimation"];
}
-(void)startLoop:(float)timeRate
{
    CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"timerIndex"];

    anim.formValue = [NSNumber numberWithInt:1]; // initial frame
    anim.toValue = [NSNumber numberWithInt:3]; // last frame + 1

    anim.duration = timeRate; // Speed of the loop, ei. 1 would be once every second
    anim.repeatCount = HUGE_VALF; //just keep repeating it

    [self addAnimation:anim forKey:@"timerAnimation"];
}

The only thing that would ever need to be changed in any of these functions is anim.duration, set this to the frequency of your execution.
That is it, you have a great loop that does not slow down the UI as it is running.