我正在编写一个可以恢复特定设备固件的应用程序。在执行此恢复代码时,我希望显示进度指示器。
这个问题当然最好通过使用多线程来解决(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/