views:

154

answers:

4

Kinda new to iPhone programming and was experimenting with threads

- (void)viewDidLoad {
    [super viewDidLoad];

    [NSThread detachNewThreadSelector:@selector(changeMain) toTarget:self withObject:nil];
    [NSThread detachNewThreadSelector:@selector(changeThread) toTarget:self withObject:nil];
}

- (void)changeMain{
    NSAutoreleasePool* arp = [[NSAutoreleasePool alloc] init];

    for (int i = 0; i < 1000000; i++) {
     [mainValue setText:[NSString stringWithFormat:@"%d",i]];
     [self.view setNeedsDisplay]; 
    }

    [arp release];
}
- (void)changeThread{
    NSAutoreleasePool* arp = [[NSAutoreleasePool alloc] init];

    for (int i = 0; i < 1000000; i++) {
     [threadValue setText:[NSString stringWithFormat:@"%d",i]];
     [self.view setNeedsDisplay];
    }

    [arp release];
}

mainValue and threadValue are both just UILabels. I expected this to run and see both labels run up to 999999 but instead it starts at some low number (what it is when the screen initally refreshing i assume), pauses for a bit, then updates to 999999. I'm thinking the screen just isn't refreshing.

Is this correct? Am I doing it wrong?

+1  A: 

The setNeedsDisplay message triggers a redraw, but it only happens during the next time the main thread becomes active. So your side threads trigger a million redraws but they are queued. As soon as the main thread continues, it "collapses" all requests into one redraw.

Most likely setNeedsDisplay just sets a flag that is checked once during each run of the main loop, so setting it 1000000 to true doesn't influence anything. Try to let the "worker threads" sleep after each iteration to give the main thread some time to redraw.

racha
A: 

I'm not sure if this will work, but you could try to force the setNeedsDisplay method to be executed on the main thread, using e.g. [self performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:YES]. This should (hopefully, i didn't test it!) update the view after every increment. You could also try to set waitUntiDone:NO, but I'm unsure what will happen then.

See here

MrMage
+1  A: 
  1. You have to perform any Cocoa Touch operations in main thread, in other case results are unpredictable.
  2. You don't have to call setNeedsDisplay manually.

So I'd recommend to use the following construction:

[threadValue performSelectorOnMainThread:@selector(setText:) withObject:[NSString stringWithFormat:@"%d",i] waitUntilDone:YES];

Additional notes: 1. 100000 runs can overflow the main thread queue so some values will disappear 2. You can use waitUntilDone:NO too

Valerii Hiora
Worked like a charm. Thanks!
ACBurk
+1  A: 

Don't use for() for animations. The for will process in the same "frame". Maybe just have an ivar i and in changeMain you can have if (i<10000) { mainValue.text = [NSString stringWithFormat:@"%d",i]; i++;} or something like that. This way the setText only happens once per "frame".

mga