multithreading - 使用performSelectorInBackground在单独的线程中处理代码时更新cocoa接口(interface)

标签 multithreading cocoa selector

我正在编写一个可以恢复特定设备固件的应用程序。在执行此恢复代码时,我希望显示进度指示器。

这个问题当然最好通过使用多线程来解决(http://stackoverflow.com/questions/1225700/can-i-start-a-thread-by-pressing-a-button-in-a -cocoa-interface-and-keep-using-in)。

我已经实现了performSelectorInBackground方法,该方法(根据文档)在单独的线程中启动指定的选择器。同时,我的 GUI 通过查询“reverter”对象从主线程更新。

但是,直到辅助线程中的代码完成执行后,GUI 似乎才会更新。我显然需要两者并行运行。这是我到目前为止所得到的 - 我非常感谢任何帮助,因为这是我第一次使用线程。

-(IBAction)pushButton:(id)sender{
 //instatiate reverter object, which does all the firmware processing
 Reverter *reverter = [[Reverter alloc] init];  

//update the GUI to show a tab with a progress indicator    
[tabView selectTabViewItemWithIdentifier:@"RevertProgressTab"];

//process revert code in a separate thread  
[reverter performSelectorInBackground:@selector(revertFirmware) withObject:nil];

//process is complete when reverter progress reaches 100
while (!([reverter progress] == 100)) {

    //check for failure
    if ([reverter hasFailed]) {
        [self showRevertFailureTab:nil];
        return;
    }
    //update the progress indicator in the interface
    [revertProgressBar setDoubleValue:(double)[reverter progress]];
    [NSThread sleepForTimeInterval:0.05];
}

[self showRevertSuccessTab:nil];    


}

我是否做了任何明显的事情会阻止 GUI 在 revertFirmware 方法运行时更新?

最佳答案

你的 while 循环

while (/*condition*/) {
    [NSThread sleepForTimeInterval:x];
}

将阻止您的 UI 更新。您的 UI 仅在您的 pushButton: 方法返回后才会更新。

我建议您开始使用异步事件模型,而不是轮询:

向您的恢复对象添加委托(delegate)

@protocol ReverterDelegate <NSObject>
- (void) reverterProgressDidUpdate:(float)progress;
@end

@interface Reverter : NSObject {
    id<ReverterDelegate> delegate;
}
@property(assign) id<ReverterDelegate> delegate;
@end

将您的 Controller 类注册为恢复器的委托(delegate)

reverter.delegate = self;

并处理该事件

- (void) reverterProgressDidUpdate:(float)progress {
    // update ui
}

在后台线程中将事件发送到主线程

- (void) revertFirmware {
    // once in a while send notifications of progress updates
    if ([self.delegate respondsToSelector:@selector(reverterProgressDidUpdate:)]) {
        [self.delegate performSelectorOnMainThread:@selector(reverterProgressDidUpdate:) withObject:[NSNumber numerWithFloat:progress] waitUntilDone:NO];
    }
}

确保将恢复器保留在某处,并在工作完成后将其释放。您现在正在泄漏 pushButton: 方法。此外,这只是对更好模型的建议。例如,您可以查看 NSOperation 和 NSOperationQueue,而不是使用 PerformSelectorInBackground。

关于multithreading - 使用performSelectorInBackground在单独的线程中处理代码时更新cocoa接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7791446/

相关文章:

objective-c - 使用 CGDisplay 显示窗口时,文本字段显示为不可编辑

java - JMS 选择器奇怪的行为

javascript - 根据复选框状态更改 jQuery UI 下拉菜单的背景颜色

c++ - 在多线程应用程序中使用 vector

ruby - 线程池中的死锁

objective-c - 什么时候应用程序状态属于核心数据而不是 NSUserDefaults?

cocoa - 如何模拟与 Finder 相同的窗口布局?

ios - 关于@selector 和 MVC

ios - 如何在应用程序在后台运行时监听锁定/解锁电话事件?

java - 处理 ThreadPoolExecutor 的异常