实现drawRect:导致整个视图更新

时间:2017-08-07 08:44:22

标签: objective-c cocoa

最近,我使用Apple的Quartz Debug来检测macOS中的屏幕更新。

据我所知,在NSView中,- (void)drawRect:(NSRect)dirtyRect中的dirtyRect参数表示视图中要更新的部分。

在我新创建的项目中,我创建了一个简单的" CustomView",它的实现非常简单,如下所示:

#import "CustomView.h"

@implementation CustomView

- (void)drawRect:(NSRect)dirtyRect {
    NSLog(@"dirtyRect:%@", NSStringFromRect(dirtyRect));

    [[NSColor blueColor] set];
    NSRectFill(dirtyRect);
}

@end

然后,我创建了一个按钮:

- (IBAction)testButtonClick:(id)sender {
    [self.customView setNeedsDisplayInRect:NSMakeRect(1, 1, 50, 50)];
}

当我点击按钮时,我在控制台中有以下日志:

2017-08-07 16:11:01.914859+0800 TestScreenUpdate[17818:728751] dirtyRect:{{1, 1}, {50, 50}}

很好。 但是当我启用Quartz Debug来检测屏幕更新时,每次单击该按钮时,整个CustomView都会更新 这是gif screenshot.

Apple的DragItemAround项目没有此问题,它只更新脏部分。

我的项目由Xcode 8.3.3创建,没有任何特殊配置。

也许drawRect:上的调用堆栈会解释一些内容:

这是我项目中drawRect:上的调用堆栈:

#0  0x00000001000017d4 in -[CustomView drawRect:]
#1  0x00007fffa4073513 in -[NSView(NSInternal) _recursive:displayRectIgnoringOpacity:inGraphicsContext:CGContext:topView:shouldChangeFontReferenceColor:] ()
#2  0x00007fffa4072eb9 in __46-[NSView(NSLayerKitGlue) drawLayer:inContext:]_block_invoke ()
#3  0x00007fffa40729e1 in -[NSView(NSLayerKitGlue) _drawViewBackingLayer:inContext:drawingHandler:] ()
#4  0x00007fffa40723a6 in -[NSView(NSLayerKitGlue) drawLayer:inContext:] ()
#5  0x00007fffabf4c5a5 in CABackingStoreUpdate_ ()
#6  0x00007fffac06b558 in ___ZN2CA5Layer8display_Ev_block_invoke ()
#7  0x00007fffac06b070 in CA::Layer::display_() ()

这是Apple在DragItemAround项目中drawRect:的调用堆栈:

#0  0x0000000100001007 in -[DraggableItemView drawRect:]
#1  0x00007fffa406cf99 in -[NSView _drawRect:clip:] ()
#2  0x00007fffa40bcf2f in -[NSView _recursiveDisplayAllDirtyWithLockFocus:visRect:] ()
#3  0x00007fffa40bd39a in -[NSView _recursiveDisplayAllDirtyWithLockFocus:visRect:] ()
#4  0x00007fffa40bd39a in -[NSView _recursiveDisplayAllDirtyWithLockFocus:visRect:] ()
#5  0x00007fffa406aad2 in -[NSView _recursiveDisplayRectIfNeededIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:topView:] ()
#6  0x00007fffa406a2af in -[NSThemeFrame _recursiveDisplayRectIfNeededIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:topView:] ()

1 个答案:

答案 0 :(得分:0)

您可能已为视图或其祖先之一启用了Core Animation图层。我认为当你更新一个图层时,窗口服务器会将整个内容看作是更新的,即使你只是重写它的一部分。

最近版本的Xcode中的Cocoa App模板默认情况下在根视图中启用图层。旧版Xcode中的模板没有,Apple的许多示例项目都是使用旧版本的Xcode创建的。

在故事板或xib中选择您的视图。然后选择查看>公用事业>显示视图效果检查器。如果为视图或其任何祖先启用了“核心动画层”,则视图将绘制到图层中。您可以尝试禁用它以查看它是否有所作为。