1

在我正在处理的程序中,我正在执行大量数据处理,并希望能够绘制自定义 NSView 以直观地表示该过程。

使用 GCD 在主线程外处理数据处理(使用 dispatch_sync 作为需要保留的顺序):

for (int i=0; i<iterations; i++) {

    dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // Add a data crunching task to the queue!
    });
}

当开始处理时,我初始化了一个计时器,用于要求自定义显示定期重绘(一旦所有处理任务完成,此计时器将失效):

-(void)onTick:(NSTimer *)timer {

    [_customView setNeedsDisplay:YES];
    // Update some other UI object (labels etc.)    
}

我可以按预期工作,但是我现在注意到的唯一问题是,如果我在同一个窗口上单击并按住按钮,或者在进程进行时开始拖动滑块,自定义视图的重绘在我放开鼠标之前被阻止!

有什么办法可以防止这种情况发生,最好不要将所有控件移动到单独的窗口上!

4

2 回答 2

4

是的,计时器在运行循环上,而在拖放/跟踪模式下,它不会被触发,因为运行循环对于普通模式不是高级的

将其添加到所需的模式中:

NSRunLoop *runloop = [NSRunLoop currentRunLoop];
NSTimer *timer = [NSTimer timerWithTimeInterval:0.1 target:self selector:@selector(myTimerAction:) userInfo:nil repeats:YES];
[runloop addTimer:timer forMode:NSRunLoopCommonModes];
[runloop addTimer:timer forMode: NSEventTrackingRunLoopMode];

编辑:runloop 基本上是苹果的 while 循环,用于将任何事件发送到应用程序。它根据所谓的模式过滤它调度的事件。

于 2012-12-18T13:32:45.863 回答
0

谢谢大家的问题,答案和评论。

使用 NSEventTrackingRunLoopMode 解决了我不断用给定参数重绘 OpenGL 视图的情况。

class MyOpenGLView: NSOpenGLView {

  var timer: Timer?

  required init?(coder: NSCoder) {
    super.init(coder: coder)

    timer = Timer.scheduledTimer(withTimeInterval: 1.0/60, repeats: true) { (t) in
      self.needsDisplay = true
    }

    let runloop = RunLoop.current
    runloop.add(timer!, forMode: .commonModes)
    // runloop.add(timer!, forMode: .eventTrackingRunLoopMode)
  }

  override func draw(_ dirtyRect: NSRect) {
    // draw moving 3D-cubes
  }

}

现在,即使我拖动滑块来更新其参数,它也会继续绘制。此外,调整窗口大小变得平滑。

对于其他解决方案“异步执行”,很有趣!我稍后会试一试。谢谢!

编辑:

我改变主意使用 NSRunLoopCommonModes (RunLoopMode.commonModes),而不是 NSEventTrackingRunLoopMode。

两者都运作良好,但 Apple 的文档暗示在我的情况下 Common Modes 更好。

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html

于 2017-08-30T09:51:10.703 回答