使用performSelectorInBackground在单独的线程中处理代码时更新cocoa接口
我正在编写一个可以恢复特定设备固件的应用程序。在执行此恢复代码时,我希望显示一个进度指示器。
当然,最好使用多线程来解决这个问题(http://stackoverflow.com/questions/1225700/can-i-start-a-thread-by-pressing-a-button-in-a-cocoa-接口并继续使用)。
我已经实现了 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 方法运行时更新的事情?
I am writing an app that can revert the firmware of a particular device. While executing this revert code, I wish to display a progress indicator.
This problem is of course best tackled with the use of multiple threads (http://stackoverflow.com/questions/1225700/can-i-start-a-thread-by-pressing-a-button-in-a-cocoa-interface-and-keep-using-in).
I have implemented the performSelectorInBackground method, which (according to the documentation) launches the specified selector in a separate thread. Meanwhile, my GUI is updated from the main thread by querying the 'reverter' object.
However, the GUI does not seem to be updating until the code in the secondary thread has finished executing. I obviously need the two to run in parallel. Here is what I've got so far - I'd be really grateful for any help as this is my first time with threading.
-(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];
}
Have I done anything obvious that would stop the GUI from being updated while the revertFirmware method runs?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
你的 while 循环
将阻止你的 UI 更新。您的 UI 仅在您的 pushButton: 方法返回后才会更新。
我建议您开始使用异步事件模型,而不是轮询:
向恢复器对象添加委托
将控制器类注册为恢复器的委托
并处理该事件
< strong>在后台线程中向主线程发送事件
确保将恢复器保留在某处,并在工作完成后释放它。您现在正在泄漏 pushButton: 方法。此外,这只是对更好模型的建议。例如,您可以查看 NSOperation 和 NSOperationQueue,而不是使用 PerformSelectorInBackground。
Your while loop
will prevent your UI from updating. Your UI will only update as soon as your pushButton: method returns.
Instead of polling I would advice you start using an asynchronous event model:
Add a delegate to your reverter object
Register your controller class as a delegate to your reverter
and handle that event
In your background thread send out events to the main thread
Make sure you retain your reverter somewhere, and release it when it's done working. You are now leaking in your pushButton: method. Also this is just a suggestion towards a better model. Instead of using performSelectorInBackground you could take a look at NSOperation and NSOperationQueue for example.