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];
}
精彩评论