简单进度条未更新 [英] Simple progress bar is not updating

查看:118
本文介绍了简单进度条未更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在实现一个Cocoa应用程序,它只是一个简单的进度栏,当我按下一个按钮时,它就会启动.

I am implementing a Cocoa Application which is just a simple progress bar that starts when I press a button.

情况是:按下按钮后,我可以看到动画是开始和停止",但是进度条不会更新该值.

The situation is: I can see Animation is Start and Stop when I press the button, but the progress bar will not update the value.

我也尝试过这里提到的解决方案,但是它不起作用:
如何更新长时间运行的循环中可可中的进度条?

I had also tried the solution mentioned here but it doesn't work:
How do I update a progress bar in Cocoa during a long running loop?

有人可以帮忙查看我的源代码中的问题吗?

Can someone help to see where is the problem in my source code?

这是我的消息来源.

SimpleProgressBar.m

#import "SimpleProgressBar.h"

@implementation SimpleProgressBar
@synthesize progressBar;

int flag=0;

-(IBAction)startProgressBar:(id)sender{

    if(flag ==0){
        [self.progressBar startAnimation:sender];
        flag=1;
    }else{
        [self.progressBar stopAnimation:sender];
        flag=0;
    }
    [self.progressBar displayIfNeeded];
    [self.progressBar setDoubleValue:10.0];

    int i=0;

    for(i=0;i<100;i++){

        NSLog(@"progr: %f",(double)i);
        [self.progressBar setDoubleValue:(double)i];
        [self.progressBar setNeedsDisplay:YES];
    }


}

@end

SimpleProgressBar.h

#import < Foundation/Foundation.h >

@interface SimpleProgressBar : NSObject{

    __weak NSProgressIndicator *progressBar;

}

@property (weak) IBOutlet NSProgressIndicator *progressBar;

-(IBAction)startProgressBar:(id)sender;
@end

非常感谢您提供任何有用的答案.

Thank you very much for any helpful answer.

更新:

这是我从解决方案中移植的内容,它不起作用:

Here is my porting from the solution and it doesn't work:

SimpleProgressBar.m

#import "SimpleProgressBar.h"

@implementation SimpleProgressBar
@synthesize progressBar;

int flag=0;

-(IBAction)startProgressBar:(id)sender{

    if(flag ==0){
        [self.progressBar startAnimation:sender];
        flag=1;
    }else{
        [self.progressBar stopAnimation:sender];
        flag=0;
    }
    [self.progressBar displayIfNeeded];
    [self.progressBar setDoubleValue:0.0];

    void(^progressBlock)(void);

    progressBlock = ^{

        [self.progressBar setDoubleValue:0.0];

        int i=0;

        for(i=0;i<100;i++){

            //double progr = (double) i / (double)100.0;
            double progr = (double) i;
            NSLog(@"progr: %f",progr);

             dispatch_async(dispatch_get_main_queue(),^{
             [self.progressBar setDoubleValue:progr];
             [self.progressBar setNeedsDisplay:YES];
             });

        }
    };

    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue,progressBlock);

}

推荐答案

更新:

一些观察结果:

  1. 令我惊讶的是,如果您想观看NSProgressIndicator的进度,则需要添加sleepForTimeInterval,否则for循环会如此快速地迭代,以至于您看不到进度指示器的进度,但是您会很快看到它最终处于最终状态.如果插入sleepForTimeInterval,则应该看到进度:

  1. It strikes me that if you want to watch the NSProgressIndicator advance, you need to add a sleepForTimeInterval or else the for loop iterates so quickly that you won't see the progress indicator advance, but rather you'll just see it quickly end up in its final state. If you insert sleepForTimeInterval, you should see it progress:

self.progressIndicator.minValue = 0.0;
self.progressIndicator.maxValue = 5.0;
[self.progressIndicator setIndeterminate:NO];

self.progressIndicator.doubleValue = 0.001; // if you want to see it animate the first iteration, you need to start it at some small, non-zero value

for (NSInteger i = 1; i <= self.progressIndicator.maxValue; i++)
{
    [NSThread sleepForTimeInterval:1.0];
    [self.progressIndicator setDoubleValue:(double)i];
    [self.progressIndicator displayIfNeeded];
}

或者,如果您想在后台线程上执行for循环,然后将更新分派回主队列:

Or, if you wanted to do the for loop on a background thread, and dispatch the updates back to the main queue:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    for (NSInteger i = 1; i <= self.progressIndicator.maxValue; i++)
    {
        [NSThread sleepForTimeInterval:1.0];
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.progressIndicator setDoubleValue:(double)i];
            [self.progressIndicator displayIfNeeded];
        });
    }
});

  • 您正在使用startAnimationstopAnimation,但是根据

  • You are using startAnimation and stopAnimation, but according to the documentation each of these "does nothing for a determinate progress indicator," so these calls seem inappropriate for this situation.


    下面我的原始答案基于


    My original answer, below, was predicated on the comment in the Threads and Your User Interface in the Threading Programming Guide, which says:

    如果您的应用程序具有图形用户界面,则建议您接收与用户相关的事件,并从应用程序的主线程启动界面更新.这种方法有助于避免与处理用户事件和绘制窗口内容相关的同步问题.某些框架(例如Cocoa)通常需要这种行为,但是即使对于那些不需要的框架,将这种行为保留在主线程上的好处是可以简化用于管理用户界面的逻辑.

    If your application has a graphical user interface, it is recommended that you receive user-related events and initiate interface updates from your application’s main thread. This approach helps avoid synchronization issues associated with handling user events and drawing window content. Some frameworks, such as Cocoa, generally require this behavior, but even for those that do not, keeping this behavior on the main thread has the advantage of simplifying the logic for managing your user interface.

    但是下面的答案(错误地)是iOS的答案,因此不适用.

    But the answer below is (incorrectly) an iOS answer, so is not applicable.

    原始答案:

    您的for循环正在主线程上运行,因此直到您让回到运行循环之前,UI更新才会出现.您也是如此快地经历了该循环,即使您正确地将其分派到后台队列中,也无法在循环浏览过程中体验进度视图的变化.

    Your for loop is running on the main thread, and thus UI updates won't appear until you yield back to the runloop. You're also going through that loop so quickly that even if you properly dispatched that to a background queue, you wouldn't experience the progress view changing as you iterate through your loop.

    因此,请在辅助线程上执行循环(例如,通过GCD或操作队列),然后将UI更新分派回主线程,而主线程现在可以自由地进行UI更新.因此,使用理论示例,您可以执行以下操作:

    So, perform the loop on a secondary thread (e.g. via GCD or operation queue) and then dispatch UI updates back to the main thread, which is now free to do UI updates. So, using your theoretical example, you could do something like:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        for (int i = 0; i < 100; i++)
        {
            [NSThread sleepForTimeInterval:0.1];
    
            dispatch_async(dispatch_get_main_queue(), ^{
                [self.progressView setProgress: (CGFloat) (i + 1.0) / 100.0 animated:YES];
            });
        }
    });
    

    请注意,只有当您执行的速度足够慢以使您看到进度视图发生更改时,才有一个循环来更新进度视图才有意义.在原始示例中,您只是从0循环到99,从而更新了进度视图.但这是如此之快,以至于在这种情况下,进度视图毫无意义.这就是为什么我上面的示例不仅在循环中使用了后台队列,而且还增加了一些延迟(通过sleepForTimeInterval).

    Note, having a loop that updates the progress view only makes sense if you're doing something slow enough for you to see the progress view change. In your original example, you're just looping from 0 to 99, updating the progress view. But that happens so quickly, that there's no point in a progress view in that case. That's why my above example not only employs a background queue for the loop, but also added a slight delay (via sleepForTimeInterval).

    让我们考虑一下进度视图的更现实的应用.例如,假设我有一个urls数组,其中包含NSURL个对象,这些对象表示要从服务器下载的项目.然后我可能会做类似的事情:

    Let's consider a more realistic application of the progress view. For example, let's say I had an array, urls, of NSURL objects that represent items to be downloaded from the server. Then I might do something like:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        for (int i = 0; i < [urls count]; i++)
        {
            // perform synchronous network request (on main queue, you should only do asynchronous network requests, but on background queue, synchronous is fine, and in this case, needed)
    
            NSError *error = nil;
            NSURLResponse *response = nil;
            NSURLRequest *request = [NSURLRequest requestWithURL:urls[i]];
            NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:response error:error];
    
            // got it; now update my model and UI on the basis of what I just downloaded
    
            dispatch_async(dispatch_get_main_queue(), ^{
                [self.progressView setProgress: (CGFloat) (i + 1.0) / [array count] animated:YES];
                // do additional UI/model updates here
            });
        }
    });
    

    这篇关于简单进度条未更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆