代码之家  ›  专栏  ›  技术社区  ›  nall

模型应该如何更新其进度的UI?

  •  2
  • nall  · 技术社区  · 15 年前

    我试图用宾语C来解决一个问题,但我不认为这个问题是语言特有的。

    我必须在一个没有UI概念的模型类中进行一些向下处理。但是,这个处理需要一些时间,我想通过进度条让用户知道状态。

    我的第一次尝试是用如下方法定义一个进程处理程序协议/接口的概念

    -startOperation;
    -updateProgress:(double)currentValue ofMax:(double)maxValue
    -endOperation;
    

    通过这种方式,我的用户界面可以实现,模型不需要知道除了有人想要进度更新以外的其他细节。当前,我的用户界面会取消隐藏一个进度条,并更新它,然后在完成后隐藏它。到现在为止,一直都还不错。

    然而,事实证明,有时这种操作处理速度非常快。这样,用户界面更新在执行时会导致相当令人不安的闪烁。我不知道手术前是快还是慢。

    我的一个想法是强迫操作至少花费一定的时间,以避免UI更改如此刺眼,但这似乎将有关UI的知识放到了模型类中,这肯定是错误的。

    这似乎是(希望)某个已知模式的一个常见问题。

    你将如何解决这个问题?

    3 回复  |  直到 15 年前
        1
  •  3
  •   Darren    15 年前

    您可以使用nstimer延迟进度条的显示,直到您的操作运行了给定的时间,比如说半秒:

    -(void)startOperation {
        // Show the progress bar in 0.5 seconds
        if (!_timer) {
            _timer = [[NSTimer scheduledTimerWithTimeInterval:0.5 
                                                       target:self 
                                                     selector:@selector(showProgressBar:) 
                                                     userInfo:nil 
                                                      repeats:NO] retain];
        }
    }
    

    在-EndOperation中,取消计时器并隐藏进度条:

    -(void)endOperation {
        [_timer invalidate]; // cancel the timer
        [_timer release];
        _timer = nil;
    
        [self hideProgressBar];
    }
    

    如果操作在0.5秒内完成,则在显示进度条之前取消计时器。

        2
  •  7
  •   Felixyz    15 年前

    Jonathan和Darren的回答涵盖了您的实际问题,但我会在标题中添加一些关于问题的内容:“模型应该如何更新其进度的UI?”

    当然,答案是它不应该,模型不应该知道 任何东西 关于显示数据的任何协议。应该有一个统一的绑定层,负责将信息从模型传播到接口。幸运的是,Cocoa已经包含了这样一种绑定机制:键值观察。

    您应该做的是在任何模型类上定义一个属性,其中进度概念是有意义的,比如 @property (assign) float progress .那么你呢 make sure the class is KVO compliant . 想要跟踪进度的控制器代码只需注册以观察该值,如下所示:

    [TheObject AddObserver:Self ForkeyPath:@“Progress”选项:0上下文:空];

    确保阅读nskeyValueObservation(kvo)非正式协议的文档。 此外,您可能还想看看Mike Ash的kvo相关注释和代码: Key-Value Observing Done Right .

        3
  •  2
  •   Jonathan Feinberg    15 年前

    通常要做的一件事是让进度条实现不立即显示自己,并根据前两次更新(或超时)应用一些启发式方法来确定它是否需要显示自己。Java就是这样 ProgressMonitor 例如,行为。(ProgressMonitor是一个很好的抽象,它将进度知识与其图形表示分离开来)。

    一旦进度小部件显示出来,你可以在一个悠闲的计时器上重新绘制它,比如说每秒10次,而不是用重新绘制来响应每个进度更改事件。