I'm manually placing a subclass of NSView into the parent view using addSubview:positioned:relativeTo. The dirtyRect passed to drawRect: is wildly incorrect. Can folks attempt to reproduce and file bugs? This is awfully close to the release of Sonoma, and I feel like folks with bezier curves (or maybe other drawing code?) in their NSView subclasses are going to experience problems.
To reproduce, place a view (I'm using an NSImageView) as a subview within a view. Then, create a subclass of NSView and draw a bezier curve in the drawRect method. Add an instance of this subclass as a subview of your original view. I'm offsetting the x value for clarity. When I build with Xcode 15 and run on Ventura or earlier, I get the correct result. Or, if I build with Xcode 14.3 and run on Sonoma I get the correct result. However, when I build in Xcode 15 and run on the RC build of Sonoma, I get a whacky result.
I get something like (origin = (x = -264, y = -146), size = (width = 480, height = 388)) for the dirtyRect in the error case, while the rect is supposed to be (origin = (x = 0, y = 0), size = (width = 48, height = 48)) (I'm basing the frame of the new view on the original image.)
Thanks!
Hi ski4funSonoma,
The dirtyRect
behavior you're seeing is expected for a view with -[NSView clipsToBounds]
set to NO
, which is now the default for Sonoma-linked applications. The AppKit release notes touch on this, but here's a little more information.
The geometry of dirtyRect
isn't too useful for determining where to draw your content. It's permissible for the dirtyRect
to refer to any geometry that the view could draw but does not currently have fresh contents for. For unclipped views, that region is allowed to extend beyond the geometry of the view itself. Although this has always been part of -drawRect:
's API contract, it used to be very common to only see dirtyRect
values that were equal to the bounds
, so we've seen a number of cases where views accidentally rely on that specific behavior.
You should use the view's bounds
as the basis for your path geometry. The dirtyRect
is primarily useful for avoiding unnecessary work; for example, you could skip the cost of building a complicated Bézier path if you know it won't intersect the dirtyRect
at all.