开发者

objective c cocoa updating gui from a separate thread

I have a thread which is incrementing the value of the variable "int count" . I want to update my UI with the new value of "int count" until I stop the increment by pressing the stop button. I've manage to update the UI but the memory footprint keep on growing. It doesn't show as a memory leak but it is an allocation problem.the heap size is being increased every time there is a call to a UI element from the thread. I can clearly see instruments leaks allocation part that I have some allocations which are only being freed when moving the Window of touching a UI element. I did not manage to solve the problem despite trying everything. If there is a better way to update UI elements with "int count" new value, feel free to let me know. Thanks

I posted the link to the cocoa project below if you want to run with instrument or allocation to see the problem or look at the source. It' a small project just a few lines.

Xcode Poject GUI UPDATE LINK

-(void) incrementCountGUI:(id)param{ // increment count and update gui
  NSAutoreleasePool *pool=[[NSAutoreleasePool alloc]init];// pool just added

    count++;
    if (count>=100) {// MAKE SURE COUNT DOESN'T GO ABOVE 100
        count=0;
    }
    [sliderDisplayOutlet setIntValue:count];// display value of count in textfield
    [sliderOutlet setIntValue:count];// move slider to value of count

    [pool release];
}


+(void) updateSliderThread:(id)param{// this thread will call incrementCountGUI method to continuously upgrade UI in the background

    NSAutoreleasePool *myThreadPool=[[NSAutoreleasePool alloc]init];
while (shoudStop==NO) {
    [ sharedAppInstance performSelectorOnMainThread:@selector(incrementCountGUI:) // update ui in main thread
                                         withObject:nil
                                      waitUntilDone:NO];
    usleep(5000);// sleep microsec; 
}   
    [myThreadPool release]; 
}

- (IBAction)stopCountAction:(id)sender {// START OR STOP counter thread

    if ([stopCountButtonOutlet state]==1) { // button depressed开发者_高级运维=>START
        shoudStop=NO;
        [NSThread detachNewThreadSelector:@selector(updateSliderThread:) toTarget:[AppController class] withObject:nil];
        [stopCountButtonOutlet setTitle: @" STOP" ];

    }
    if ([stopCountButtonOutlet state]==0){//button depressed=> STOP thread

        shoudStop=YES;

        [stopCountButtonOutlet setTitle:@" START INCREMENTING COUNT FROM THREAD "];

    }


}

- (IBAction)sliderAction:(id)sender { // you can change the value of the variable count manualy.
 count=[sliderOutlet intValue];
[sliderDisplayOutlet setIntValue:count];// display value of count


}


1) First of all, you should never update the UI from a thread other than the main thread !

_Post a notification to the mainThread to ask it to update the UI, or use performSelector:onMainThread: or GCD and get_main_queue(), or whatever solution to make the main thread update the UI.

[EDIT] Sorry I missed the part of your code where you call performSelectorOnMainThread: so that's OK.


2) Moreover, using a thread for what you need is really not necessary. In general you should avoid thread, an prefer other techniques like NSOperationQueues, GCD, or even RunLoop scheduling.

In your case, using a thread an usleep(5000) is just overhead and will arise a lot of problems related to multithreading (read Apple's Concurrency Programming Guide and Threading Programming Guide).

You could do the same thing using a repeating NSTimer, it will be much more easier to code and manage, and will avoid you a lot of trouble.


Hmm.. let's try to release behind-the-scene objects created by performSelectorOnMainThread calls, if any.

+(void) updateSliderThread:(id)param
{
    NSAutoreleasePool *myThreadPool=[[NSAutoreleasePool alloc]init];
    int drainCount = 0;   
    while (shoudStop==NO)
    {
        [ sharedAppInstance performSelectorOnMainThread:@selector(incrementCountGUI:)
                                             withObject:nil
                                          waitUntilDone:NO];
        usleep(5000);// sleep microsec; 

        // Release pooled objects about every 5 seconds
        if (++drainCount >= 1000)
        {
            [myThreadPool release];
            myThreadPool = [[NSAutoreleasePool alloc]init];
            drainCount = 0;
        }
    }   
    [myThreadPool release]; 
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜