【问题标题】:Calling -setNeedsDisplay:YES from within -drawRect?从 -drawRect 中调用 -setNeedsDisplay:YES?
【发布时间】:2012-05-12 22:50:12
【问题描述】:

我正在自定义我的 drawRect: 方法,如果它已“加载”,则该方法用于绘制 NSImage(加载需要几秒钟的时间,因为我从 WebView 获取它),并且如果图像尚未加载,则推迟绘制图像。

- (void)drawRect:(NSRect)dirtyRect
{
    NSImage *imageToDraw = [self cachedImage];
    if (imageToDraw != nil) {
        [imageToDraw drawInRect:dirtyRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0 respectFlipped:YES hints:nil];
    } else {
        //I need help here
        [self setNeedsDisplay:YES];
    }
}

我的问题是如何做后者。 [self cachedImage] 如果图像不可用,则返回nil,但在接下来的几秒钟内,它可能随时可用,那时我想绘制它,因为自定义视图已经在屏幕上。

我最初的直觉是,如果图像不可用,我会尝试调用[self setNeedsDisplay:YES];,希望它会告诉 Cocoa 下次再调用drawRect(一次又一次,直到图像被绘制出来),但这不起作用。

关于我可以从这里去哪里的任何指示?


编辑:

我非常清楚 WebView 的委托方法会在 loadRequest 完全处理后触发。然而,由于应用程序其余部分的结构,使用这些将非常困难,但我想我现在会尝试以某种方式使用它们,因为目前的答案。 (另请注意,我的 drawRect: 方法的重量相对较轻,除了上面已有的代码 除了之外什么都没有。)

我目前有大约 10 多个自定义视图,每个视图都有自定义数据,要求相同的 WebView 为每个视图生成图像。同时,我从 NSCache 中获取图像(使用与每个自定义视图对应的标识符)并在它不存在或需要更新时创建它,如果它还不可用则返回 nil。因此,它不像从 - (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame 或其他方法调用 [view setNeedsDisplay:YES] 那样简单。

【问题讨论】:

  • 你到底是如何抓取这张图片的?
  • -drawRect: 不应该有副作用。它应该只根据视图的当前状态进行绘制,并且应该尽可能高效地进行绘制。在 -drawRect: 中发送 -setNeedsDisplay: 消息将导致每次通过主事件循环时都重新绘制视图。

标签: objective-c cocoa osx-lion nsview drawrect


【解决方案1】:

我最初的直觉是尝试调用 [self setNeedsDisplay:YES];如果图像不可用,希望它会告诉 Cocoa 下次再次调用 drawRect(一次又一次,直到图像被绘制)

这将是非常低效的,即使它有效。

在接下来的几秒钟内它可能随时可用,那时我想画它

所以,如果发生这种情况,请致电[view setNeedsDisplay:YES]

如果您无法直接确定图像何时可用,则必须进行轮询。设置一个重复的NSTimer,间隔合理——比如 0.25 秒左右。 (这也是相当低效的,但至少它每秒只运行 4 次,而不是 60 次或更糟。这是两个因素之间的权衡:您想要使用多少 CPU 和电池电量,以及时间之间的延迟时间图像变为可用以及您显示它的时间。)

我的drawRect:方法比较轻量,除了我上面已经有的代码什么都没有。

即使你在-drawRect: 中什么都不做,Cocoa 仍然需要在幕后做很多工作——它需要管理脏矩形,清除窗口后备存储的适当区域,将其刷新到屏幕等。这些都不是免费的。

【讨论】:

  • 我认为这是一个糟糕的解决方案。 WebView 在事件发生时发送通知,并且应该实现一个委托来捕获这些事件并调用 [view setNeedsDisplay:YES]。这里不需要 NSTimer!
  • 当然。这就是我所说的“当这种情况发生时”的意思:如果您可以使用委托方法或通知,那么当然使用它。如果没有这样的方法,你将不得不以一种效率较低的方式来做。 OP没有具体说明是哪种情况。
  • 是的。这被标记为可可,此类通知由 WebView 发送。否则,轮询它当然是一个可行的解决方案。
  • 好吧,既然你这么说!是时候重组我的应用了~谢谢。
【解决方案2】:

嗯,当下载完成时,通常会调用一些委托方法。您应该实现该方法并在那里调用setNeedsDisplay:YES

【讨论】:

    【解决方案3】:

    webkit 的文档:

    https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/DisplayWebContent/Tasks/ResourceLoading.html#//apple_ref/doc/uid/20002028-CJBEHAAG

    您必须在您的 webview 委托中实现以下方法:

     - webView:resource:didFinishLoadingFromDataSource: 
    

    在那里你可以拨打[view setNeedsDisplay:Yes]

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多