views:

63

answers:

2

I need help with some programming logic... I need to loop this method to display the math problem in my labels then sleep(5) and then loop again. Anything I've tried ends of freezing the program. PLEASE help! I've been tearing my hair out trying everything I know!

EDIT: I edited the code to this, After 3 seconds it fades away the label displaying the problem but then it crashed and the debugger displays 2010-08-06 10:43:27.776 Reactor [13444:207] modifying layer that is being finalized - 0x5c13500

//quickfire problems
-(void)simpleMath{ //"Tap when the answer is X"
    isTimeToTap = NO;
    int problemSelector = arc4random() % 4;

    NSArray *mathProblems = [[NSArray alloc] initWithObjects:@"6 - 1",@"2 + 3",@"3 x 2",@"3 x 1",@"2 x 4",nil]; //correct index 2
    NSArray *mathAnswers = [[NSArray alloc] initWithObjects:@"5",@"5",@"6",@"3",@"8",nil]; //correct index 2

    if ([mathAnswers objectAtIndex:problemSelector] == @"6") {
        isTimeToTap = YES;
    }

    if (ranBefore == NO) { //create labels

        //tell when to tap
        tapTellerTop.text = @"Tap when the answer is 6!";
        tapTellerBottom.text = @"Tap when the answer is 6!";

        //make bottom label
        mathDisplayBottom = [[UILabel alloc] initWithFrame:CGRectMake(15, 250, 242, 92)];
        mathDisplayBottom.font = [UIFont fontWithName:@"Helvetica" size: 96.0];
        mathDisplayBottom.textColor = [UIColor whiteColor];
        mathDisplayBottom.backgroundColor = [UIColor clearColor]; 
        [self.view addSubview: mathDisplayBottom];

        //make top label
        mathDisplayTop = [[UILabel alloc] initWithFrame:CGRectMake(55, 120, 242, 92)];
        mathDisplayTop.font = [UIFont fontWithName:@"Helvetica" size: 96.0];
        mathDisplayTop.textColor = [UIColor whiteColor];
        mathDisplayTop.backgroundColor = [UIColor clearColor];
        [self.view addSubview: mathDisplayTop];
        //rotate top label
        mathDisplayTop.transform = CGAffineTransformMakeRotation(180.0 /180.0 * M_PI);
    }
    //if ran before just update the text 
    mathDisplayBottom.text = [mathProblems objectAtIndex:problemSelector];
    mathDisplayTop.text = [mathProblems objectAtIndex:problemSelector];

    ranBefore = YES; //if its here. its been ran.

    //run timer wait for (3) then loop again until userTaps = YES
    [self performSelector:@selector(simpleMath) withObject:nil afterDelay:3.0f];

    [mathProblems release];
    [mathAnswers release];
    [mathDisplayBottom release];
    [mathDisplayTop release];
}
A: 

You shouldn't sleep(), ever. To invoke a function repeatedly, call:

[NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(doStuff:)
                                                userInfo:nil repeats:YES];

then define the function:

-(void)doStuff:(NSTimer*)timer
{
    // stuff
    if ( iAmDone ) [timer invalidate];
}

OR if you want to fire another call, after 5 seconds, you could call

if ( !iAmDone ) [self performSelector:@selector(simpleMath) afterDelay:5];

at the end of simpleMath.

mvds
alright. Why can't i use it? and what about my loop problem?
The control of the flow in your program is handled by the objective C runtime, in something called a run loop. This handles passing messages back and forth, and timing certain actions. After your methods are done and return, the runtime can continue doing its job. If your method calls `sleep()` it effectively blocks that process, by not handing back control. So you have to use other methods.
mvds
Ok, so it can be used just not in this situation?
I can be used (you already proved that, since your app froze?) but you *should* never use it. There are other solutions, such as the two proposed above.
mvds
Oh alright. I edited my original post if could you help me?
A: 

Sleep will stop your application from running or responding at all. Here is a quick partial example of a view controller you could use. This assumes you wire up the tap button and only uses one of the labels, etc. but you can play around with it. Also, this won't deal with memory issues or anything, so you'd add support for that.

But, once this view controller is created and the view installed, the math problem will update every 5 seconds. If the user presses the button and the answer is valid, we log a success message, otherwise we log fail message.

@interface myMathController : UIViewController {
    NSArray* mathProblems;
    NSIndexSet* validIndexes;
    NSUInteger currentIndex;

    NSTimer* timer;
}

@property(nonatomic,assign) IBOutlet UILabel* mathDisplayLabel;

- (void)updateProblem:(NSTimer*)timer;
- (IBAction)userTap;

@end

@implementation myMathController

- (void)viewDidLoad
{
    [super viewDidLoad];
    mathProblems = [[NSArray alloc] initWithObjects:@"6 - 1",@"2 + 3",@"3 x 2",@"3 x 1",@"2 x 4",nil];
    // Add all valid answers
    NSMutableIndexSet* tempIndexes = [[NSMutableIndexSet alloc] init];
    [tempIndexes addIndex:2];
    validIndexs = [tempIndexes copy];
    [tempIndexes release];

    timer = [[NSTimer alloc] initWithFireDate:[NSDate date] interval:5.0 target:self selector:@selector(updateProblem:) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}

- (void)updateProblem:(NSTimer*)timer
{
    currentIndex = arc4random() % [mathProblems count];
    [mathDisplayLabel setText:[mathProblems objectAtIndex:currentIndex]];
}

- (void)userTap
{
    if( [validIndexes containsIndex:currentIndex] ) {
        NSLog(@"This user is SMART!");
    } else {
        NSLog(@"This user needs more work!");
    }
}

- (void)dealloc
{
    [timer invalidate];
    [timer release];
    [mathProblems release];
    [validIndexes release];
    [super dealloc];
}

@end
Jason Coco