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

发布于 2024-12-10 04:00:37 字数 1290 浏览 2 评论 0原文

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

当然,最好使用多线程来解决这个问题(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 技术交流群。

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

发布评论

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

评论(1

安静 2024-12-17 04:00:37

你的 while 循环

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

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

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

向恢复器对象添加委托

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

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

将控制器类注册为恢复器的委托

reverter.delegate = self;

并处理该事件

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

< strong>在后台线程中向主线程发送事件

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

Your while loop

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

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

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

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

Register your controller class as a delegate to your reverter

reverter.delegate = self;

and handle that event

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

In your background thread send out events to the main thread

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

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.

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