如何从后台线程更新cocoa应用程序中的UI控件

Ami*_*Sri 2 cocoa notifications multithreading objective-c

以下是.m代码:

#import "ThreadLabAppDelegate.h"
@interface ThreadLabAppDelegate()

- (void)processStart;
- (void)processCompleted;

@end


@implementation ThreadLabAppDelegate

@synthesize isProcessStarted;

- (void)awakeFromNib {
    //Set levelindicator's maximum value
    [levelIndicator setMaxValue:1000];
}

- (void)dealloc {
    //Never called while debugging ????
    [super dealloc];
}

- (IBAction)startProcess:(id)sender {
    //Set process flag to true
    self.isProcessStarted=YES;

    //Start Animation
    [spinIndicator startAnimation:nil];

    //perform selector in background thread
    [self performSelectorInBackground:@selector(processStart) withObject:nil];
}

- (IBAction)stopProcess:(id)sender {
    //Stop Animation
    [spinIndicator stopAnimation:nil];

    //set process flag to false
    self.isProcessStarted=NO;
}

- (void)processStart {
    int counter = 0;
    while (counter != 1000) {
        NSLog(@"Counter : %d",counter);

        //Sleep background thread to reduce CPU usage
        [NSThread sleepForTimeInterval:0.01];

        //set the level indicator value to showing progress
        [levelIndicator setIntValue:counter];

        //increment counter
        counter++;
    }

    //Notify main thread for process completed
    [self performSelectorOnMainThread:@selector(processCompleted) withObject:nil waitUntilDone:NO];

}

- (void)processCompleted {
    //Stop Animation
    [spinIndicator stopAnimation:nil];

    //set process flag to false
    self.isProcessStarted=NO;
}
@end 
Run Code Online (Sandbox Code Playgroud)

我需要按照上面的代码清除以下内容.

  1. 如何从UI控件循环中断/取消processStart?
  2. 我还需要在主UI中显示计数器值,我想这与performSelectorOnMainThread和传递参数有关.只是想知道,有没有其他方法可以做到这一点?
  3. 当我的应用程序启动时,它在Activity Monitor中显示1个线程,但是当我在后台线程中启动processStart()时,它创建了两个新线程,这使得总共3个线程直到或除非循环结束.完成循环后我可以看到2个主题.所以,我的理解是,当我调用performSelectorInBackground时创建了2个线程,但是从哪里创建了thrid线程呢?
  4. 如果线程计数在每次调用选择器时都会增加怎么办?如何控制或者我的实现对这种要求有害?

谢谢

Pet*_*sey 6

如何从后台线程更新cocoa应用程序中的UI控件

简单:不要.

如何从UI控件循环中断/取消processStart?

在外面processStart,设置一个标志变量.在里面processStart,检查该标志并退出循环(如果已设置).

不要试图从另一个线程"杀死"一个线程.这总是一个坏主意.通过设置标志告诉线程是时候停止,并让线程检查该标志并在适当的时间停止.

我还需要在主UI中显示计数器值,我想这与performSelectorOnMainThread和传递参数有关.只是想知道,有没有其他方法可以做到这一点?

是.

当我的应用程序启动时,它在Activity Monitor中显示1个线程,但是当我在后台线程中启动processStart()时,它创建了两个新线程,这使得总共3个线程直到或除非循环结束.完成循环后我可以看到2个主题.所以,我的理解是,当我调用performSelectorInBackground时创建了2个线程,但是从哪里创建了thrid线程呢?

使用Instruments或Shark描述您的应用程序并查看.它可能是进度指示器的心跳线程.

如果线程计数在每次调用选择器时都会增加怎么办?如何控制或者我的实现对这种要求有害?

每条performSelectorInBackground:withObject:消息都会启动一个帖子 如果你的线程数没有下降,那是因为你的线程方法没有退出.如果您的线程数太高,那么(可能)是因为您启动了太多线程.


有一个更好的方法来做到这一点.

首先,可可的一般规则是从不睡觉.将此视为特殊的超含咖啡因的可可.对于你可能在另一个框架中睡觉的任何东西,在Cocoa中几乎总会有更好的,通常更简单的方式.

考虑到这一点,请看一下processStart.它所做的就是每隔一分钟做一些事情.怎么做到最好?

Cocoa有一个用于此特定目的的类:NSTimer.创建一个计时器,以所需的间隔向自己发送消息,并通过更新进度条来响应该消息 - 也就是说,您的计时器回调方法应该基本上只是循环体processStart,而不是循环.

顺便说一句,每秒100次更新是过度的.首先,用户并不关心自上次更新条形码以来你已经取得了1/5像素的进步.其次,屏幕每秒仅更新大约60次,因此更新任何比这更快的内容都是毫无意义的.

- (void)dealloc {
    //Never called while debugging ????
    [super dealloc];
}
Run Code Online (Sandbox Code Playgroud)

假设您将应用程序委托放在MainMenu nib中,应用程序对象因此而拥有它 - 但它不知道这一点,因为它只知道应用程序委托作为其委托,这是一种非拥有关系.(即使它是一个拥有的关系,这只是两个所有权,应用程序将释放一个,这将无济于事.)

但是,应用代表的生命周期并不重要.它作为应用程序的委托的目的意味着它只需要应用程序就可以持续一段时间,但是当应用程序消失时,进程就会退出,这意味着委托也将被释放,作为回收的一部分.进程的内存空间.这就是为什么dealloc不被调用 - 整个进程空间立即消失,而不是一次一个地释放对象.

因此,原则上,是的,应用程序代表没有明确清理是有点狡猾.在实践中,不要在其中放置任何临时文件dealloc(使用applicationWillTerminate:相反),你会没事的.

我通常通过将所有实际工作放在app委托拥有的一个或多个其他对象中来解决问题.应用程序委托创建这些其他控制器applicationWillFinishLaunching:并将其释放applicationWillTerminate:,因此这些对象会获取dealloc消息.问题解决了.