Objective C Cocoa 从单独的线程更新 gui

发布于 2024-12-07 09:52:13 字数 2140 浏览 0 评论 0原文

我有一个线程正在增加变量“int count”的值。我想用“int count”的新值更新我的用户界面,直到我通过按停止按钮停止增量。我已设法更新用户界面,但内存占用量不断增加。它并不显示为内存泄漏,而是一个分配问题。每次从线程调用 UI 元素时,堆大小都会增加。我可以清楚地看到仪器泄漏分配部分,我有一些分配,只有在移动触摸 UI 元素的窗口时才会被释放。尽管尝试了一切,我还是没能解决这个问题。 如果有更好的方法用“int count”新值更新 UI 元素,请随时告诉我。 谢谢,

如果您想使用仪器或分配运行来查看问题或查看源代码,我在下面发布了可可项目的链接。这是一个小项目,只有几行代码。

Xcode Poject GUI 更新链接

-(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


}

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


}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

还给你自由 2024-12-14 09:52:13

1) 首先,您不应该从主线程以外的线程更新 UI!

_向 mainThread 发布通知,要求其更新 UI,或使用 performSelector:onMainThread: 或 GCD 和 get_main_queue(),或任何使主线程更新的解决方案用户界面。

[编辑] 抱歉,我错过了您调用 performSelectorOnMainThread: 的代码部分,所以没关系。


2)此外,使用线程来满足您的需要确实没有必要。一般来说,您应该避免线程,而更喜欢其他技术,例如 NSOperationQueues、GCD,甚至 RunLoop 调度。

在您的情况下,使用线程 usleep(5000) 只是开销,并且会产生许多与多线程相关的问题(请阅读 Apple 的并发编程指南和线程编程指南)。

你可以使用重复的NSTimer来做同样的事情,它会更容易编码和管理,并且会避免你很多麻烦。

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.

若能看破又如何 2024-12-14 09:52:13

嗯..让我们尝试释放由 performSelectorOnMainThread 调用创建的后台对象(如果有)。

+(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]; 
}

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]; 
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文