NSScrollView calls drawRect on custom views for every frame

I have lots of experience with iOS, but I am new to MacOS development.

I am using NSScrollView to scroll multiple instances of a custom subclass of NSView. This custom subclass has a custom drawRect implementation. So multiple instances of this subclass are displayed at once (can even be up to 100 instances).

Everything works fine, but when I scroll I notice that it is not doing it very smoothly. By placing an NSLog() statement inside the drawRect implementation I soon found out it is getting called for each frame during scrolling.

What I am used to on iOS is that drawRect is called once, and the contents are never redrawn unless you ask for it by calling setNeedsDisplay.

I want to improve the performance of my NSScrollView by not making my custom NSViews redraw lots of times during scrolling, but instead remember what was last drawn. How can it be done?

I figured out a way to make it draw everything only once! I am now using an NSImage to draw everything on once. I only do this again when the model changes.

buffer = [[NSImage alloc] initWithSize:self.bounds.size];
[buffer lockFocus];
[self drawStuff];
[buffer unlockFocus];

After that I simply draw that image onto screen, which appears to be way faster.

- (void) drawRect:(NSRect) dirtyRect {
    [buffer drawInRect:self.bounds];
}

NSScrollView calls drawRect on custom views for every frame, I figured out a way to make it draw everything only once! I am now using an NSImage to draw everything on once. I only do this again when the model changes. •Only do drawing in -drawRect: No network calls No image allocation or loading No file access No layout (adding/removing subviews) •Hiding views may be faster than adding/removing them Utilize setHidden: when necessary Exceptions: Layer-backed views

It 'might' help to set [scrollView.contentView setCopiesOnScroll:YES]; if your drawRect is very performance intensive.

Optimizing View Drawing, By placing an NSLog() statement inside the drawRect implementation I soon found out it is getting called for each frame during scrolling. What I am used to on � I have an NSScrollView with a custom NSView subclass in it (created from IB). It draws just fine, but if I set the content view to scroll to the top, then call the scroll view's reflectScrolledClipView: method, it performs the scroll, but doesn't show the contents of the view. I have to either scroll down slightly, or resize the window.

set wantslayer to yes. on ios it's turned on by default.

Creating a Custom View, Explains how to design and implement Cocoa views in applications. Advanced Custom View Tasks � Determining the Output Device� If you are implementing a custom scroll view or you want some additional UI based on the state of the view group, you can use this to draw on top of everything. Drawables The next object that we can start drawing with a Canvas is in drawables.

objective c, Creating a Custom View. The NSView class acts mainly as an abstract superclass; generally you create instances of its subclasses, not of� An application typically marks a view or a portion of a view as requiring update. At the end of the event loop or in response to an explicit display request, the view machinery locks focus on the view and calls the view's drawRect: method to cause the view to be redrawn. By coalescing update requests in this manner, an application can reduce

[PDF] custom views, By placing the NASOL () statement in the drawRect implementation, I soon came to know that it is called for every frame during scrolling. What I am used in iOS� Optimizing Drawing and Scrolling on OS X Session 215 WWDC 2013 Creating a responsive app requires fast drawing and smooth scrolling. Discover techniques to optimize drawing, find out best practices for handling layers, and learn how to combine those techniques with new features to achieve smooth scrolling.

Understanding Scroll Views � objc.io, NSTextField, NSTableView, and NSColorWell are all views. (Note that a window is Notice that your view knows its location as an NSRect called bounds. I am making a procedural material. I wanted to animate the scale value. I wanted to animate in such a way that the scale value changes to the frame number every time the frame number is a multiple of 10, so I scripted the following: import bpy frame_num = bpy.context.scene.frame_current if frame_num % 10 == 0: bpy.data.materials["noise"].node_tree.nodes["White Noise Texture"].inputs[1].default

Comments
  • Does drawRect get called even when not scrolling? This seems normal(at least to me) My NSScrollViews do the same. It might help to move all CPU intensive code out of drawRect and just have it draw its contents.
  • I considered this initially. I assume you don't have interactivity?
  • How does re-sizing work when you use an NSImage? Run into issues?
  • I just measured how much faster it is. The normal drawing takes 0,276ms on average, while drawing the image takes 0,096ms on average.
  • I don't have interactivity at this moment but I will have it in the future. I don't think it will cause a problem because I can simply update the buffer image every time I need the drawing to change. And as for resizing... it might cause problems. I am rendering all this in an NSPopover at the moment so it is not easy for me to check how resizing behaves.
  • I think that for resizing you could implement - (void) resizeSubviewsWithOldSize:(NSSize) oldSize to update the image buffer.
  • Thanks for your suggestion! Unfortunately setting that property has no effect :( drawRect is still called just as often.
  • have you profiled your drawRect calls? You are doing something unnecessary if it takes more than a few milliseconds.
  • I just did. Each NSView takes less than 1 millisecond to render. The problem is that there are like 40 instances of this NSView visible at once.
  • I ran into an upper-limit of NSTextViews inside the documentView of the NSScrollView. I ended up rendering all of them in the documentView's drawRect significantly reducing overhead.
  • How did you approach rendering them all at once? Calling all drawRect's directly?