Re: drawRect runs twice, bounds are changed in between
Thank you. On Jan 28, 2015, at 8:30 PM, Graham Cox graham@bigpond.com wrote: On 29 Jan 2015, at 3:05 pm, N!K pu56ucl...@alumni.purdue.edu wrote: NSBezierPath* temp; is in the list of declarations. This snippet is in drawRect: NSAffineTransform* tfm = [[NSAffineTransform alloc] init]; [tfm scaleXBy:scaleX yBy:scaleY]; temp = [tfm transformBezierPath:_path]; NSLog(@“\n\n temp = %p\n\n,temp); I hope ARC keeps cleaning them up. Or do I have a memory leak? If so, I’d appreciate some guidance on how to fix it. You're fine leaks-wise, but your code might be cleaner. The bezier path returned by [tfm transformBezierPath] is autoreleased. ARC cleans up tfm, temp is released at the end of the event cycle. If temp is an ivar, and it's not used anywhere else, just make it a local var (it will be stale after the event cycle completes anyway). If it's an ivar and it is referenced elsewhere, you probably should make it a strong property instead. --Graham ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: drawRect runs twice, bounds are changed in between
Uti, Looking further into your uncertainty about where temp comes from (see previous email, below) reveals a possible memory leak. NSBezierPath* temp; is in the list of declarations. This snippet is in drawRect: NSAffineTransform* tfm = [[NSAffineTransform alloc] init]; [tfm scaleXBy:scaleX yBy:scaleY]; temp = [tfm transformBezierPath:_path]; NSLog(@“\n\n temp = %p\n\n,temp); drawRect runs many times while dragging the corner of the window. transformBezierPath: creates a new object each time. A new temp is created each time. Just one memory location is not used repeatedly. Here’s a list of temp addresses — not temp content — (from NSLog %p above) while dragging the corner of the window slightly. They are all different. 2015-01-28 16:27:44.042 CVone[780:303] temp = 0x608000320960 2015-01-28 16:27:44.094 CVone[780:303] temp = 0x60800013fd60 2015-01-28 16:27:49.465 CVone[780:303] temp = 0x6080003212c0 2015-01-28 16:27:49.484 CVone[780:303] temp = 0x6013ff40 2015-01-28 16:27:49.501 CVone[780:303] temp = 0x608000321180 2015-01-28 16:27:49.523 CVone[780:303] temp = 0x608000320be0 2015-01-28 16:27:49.541 CVone[780:303] I hope ARC keeps cleaning them up. Or do I have a memory leak? If so, I’d appreciate some guidance on how to fix it. Nick On Jan 16, 2015, at 5:30 AM, Uli Kusterer witness.of.teacht...@gmx.net wrote: On 15 Jan 2015, at 07:58, Quincey Morris quinceymor...@rivergatesoftware.com wrote: Putting those two ideas together leads to a better approach. Create the bezier path once, relative to an arbitrary bounding rect — say 1000 x 1000. (But any rect would do.) When you need to draw the path, set the CTM of the context to scale 1000 x 1000 (the reference bounds) to the context’s width x height (the view bounds). Then just draw the original path and AppKit will scale the bezier path for you. That's not the be-all end-all, though. Scaling the CTM scales line widths and heights as well. So if you for example want to skew the path, you'd get lines that are wider than they are tall (kind of calligraphic). Also, changing the CTM means that mouse click coordinates will be in a different coordinate system then your drawing, so if you’re e.g. implementing a graphics editor, you'll have to manually translate the coordinates each time. A better idea might be to have a list of original objects and projected objects. The list of projected objects is generated by transforming the paths. Whenever your view's bounds change, you rebuild this list of projected objects from the originals (thus keeping rounding errors etc. to a minimum as they can't accumulate). The drawing code just draws this projected list. As I don't know where 'temp' comes from in N!K’s code, NSBezierPath* temp; is in the list of declarations. _path is created once, in -(id)initWithCoder:(NSCoder*)coder . _path is scaled to the new size and assigned to temp each time drawRect is called. Thus, there is no error buildup. this may be what's already happening, in which case I find that a better approach than mangling the CTM if your interest is in having a shape drawn crisply in a window. If you're instead looking to scale a drawing (whether vector or otherwise), where you want lines to be skewed, then Quincy.s approach is preferrable. -- Uli Nick ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: drawRect runs twice, bounds are changed in between
On 29 Jan 2015, at 3:05 pm, N!K pu56ucl...@alumni.purdue.edu wrote: NSBezierPath* temp;is in the list of declarations. This snippet is in drawRect: NSAffineTransform* tfm = [[NSAffineTransform alloc] init]; [tfm scaleXBy:scaleX yBy:scaleY]; temp = [tfm transformBezierPath:_path]; NSLog(@“\n\n temp = %p\n\n,temp); I hope ARC keeps cleaning them up. Or do I have a memory leak? If so, I’d appreciate some guidance on how to fix it. You're fine leaks-wise, but your code might be cleaner. The bezier path returned by [tfm transformBezierPath] is autoreleased. ARC cleans up tfm, temp is released at the end of the event cycle. If temp is an ivar, and it's not used anywhere else, just make it a local var (it will be stale after the event cycle completes anyway). If it's an ivar and it is referenced elsewhere, you probably should make it a strong property instead. --Graham ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: drawRect runs twice, bounds are changed in between
On Jan 16, 2015, at 5:30 AM, Uli Kusterer witness.of.teacht...@gmx.net wrote: On 15 Jan 2015, at 07:58, Quincey Morris quinceymor...@rivergatesoftware.com wrote: Putting those two ideas together leads to a better approach. Create the bezier path once, relative to an arbitrary bounding rect — say 1000 x 1000. (But any rect would do.) When you need to draw the path, set the CTM of the context to scale 1000 x 1000 (the reference bounds) to the context’s width x height (the view bounds). Then just draw the original path and AppKit will scale the bezier path for you. That's not the be-all end-all, though. Scaling the CTM scales line widths and heights as well. So if you for example want to skew the path, you'd get lines that are wider than they are tall (kind of calligraphic). Also, changing the CTM means that mouse click coordinates will be in a different coordinate system then your drawing, so if you’re e.g. implementing a graphics editor, you'll have to manually translate the coordinates each time. A better idea might be to have a list of original objects and projected objects. The list of projected objects is generated by transforming the paths. Whenever your view's bounds change, you rebuild this list of projected objects from the originals (thus keeping rounding errors etc. to a minimum as they can't accumulate). The drawing code just draws this projected list. As I don't know where 'temp' comes from in N!K’s code, NSBezierPath* temp; is in the list of declarations. _path is created once, in -(id)initWithCoder:(NSCoder*)coder . _path is scaled to the new size and assigned to temp each time drawRect is called. Thus, there is no error buildup. this may be what's already happening, in which case I find that a better approach than mangling the CTM if your interest is in having a shape drawn crisply in a window. If you're instead looking to scale a drawing (whether vector or otherwise), where you want lines to be skewed, then Quincy.s approach is preferrable. -- Uli Nick ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: drawRect runs twice, bounds are changed in between
On 15 Jan 2015, at 07:58, Quincey Morris quinceymor...@rivergatesoftware.com wrote: Putting those two ideas together leads to a better approach. Create the bezier path once, relative to an arbitrary bounding rect — say 1000 x 1000. (But any rect would do.) When you need to draw the path, set the CTM of the context to scale 1000 x 1000 (the reference bounds) to the context’s width x height (the view bounds). Then just draw the original path and AppKit will scale the bezier path for you. That's not the be-all end-all, though. Scaling the CTM scales line widths and heights as well. So if you for example want to skew the path, you'd get lines that are wider than they are tall (kind of calligraphic). Also, changing the CTM means that mouse click coordinates will be in a different coordinate system then your drawing, so if you're e.g. implementing a graphics editor, you'll have to manually translate the coordinates each time. A better idea might be to have a list of original objects and projected objects. The list of projected objects is generated by transforming the paths. Whenever your view's bounds change, you rebuild this list of projected objects from the originals (thus keeping rounding errors etc. to a minimum as they can't accumulate). The drawing code just draws this projected list. As I don't know where 'temp' comes from in N!K's code, this may be what's already happening, in which case I find that a better approach than mangling the CTM if your interest is in having a shape drawn crisply in a window. If you're instead looking to scale a drawing (whether vector or otherwise), where you want lines to be skewed, then Quincy.s approach is preferrable. -- Uli ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: drawRect runs twice, bounds are changed in between
Would the Managing Live Resize methods of NSView (https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSView_Class/#//apple_ref/doc/uid/2014-SW41) be helpful? The docs for -viewWillStartLiveResize suggest that that would be a good place to prepare for a resize instead of trying to manage how has the size changed decisions in -drawRect:. On Jan 14, 2015, at 8:39 PM, N!K pu56ucl...@alumni.purdue.edu wrote: On Jan 13, 2015, at 10:50 PM, Jens Alfke j...@mooseyard.com wrote: On Jan 13, 2015, at 9:25 PM, N!K pu56ucl...@alumni.purdue.edu wrote: A breakpoint at the end of drawRect shows that it runs twice. After the second pass, the view appears, as it should. Between passes, bounds is changed somehow, as shown by NSLog at the start and end of drawRect. Since this will upset code that I will add later, I’d like to stop this. The view's being resized, probably as part of view layout. Ideally AppKit shouldn't draw the view before it gets to its final size, but maybe this is part of an animation, or maybe it's something that hasn't been optimized 100% in AppKit. In general, you should not make assumptions about when and how often -drawRect: will be called. That's up to AppKit. Your job is just to draw the view when you’re told to. OK. Cause is unknown (probably unknowable?) but part of Cocoa. Just because there was only one pass in other projects, I can’t depend on it. drawRect can happen anytime. You haven't said why the bounds change will upset your code; is the view being changed to the wrong size? That would be an actual problem, but it isn't related to being drawn multiple times. You'd need to look at the view constraints in your window to diagnose that. —Jens “Why” takes a little explaining. Thank you for your patience. I’m trying to learn more about drawing. One stumbling block was getting an NSBezierPath to change size proportional to the window size when the corner is dragged. Per Graham Cox’s suggestion, the view size change can be detected in subsequent passes of drawRect by comparing ratioX = NSWidth ([_path bounds])/NSWidth(bounds); ratioY = NSHeight([_path bounds])/NSHeight(bounds); with their initial values, which were established in the one pass of drawRect before the view appeared. This worked perfectly. I used the ratios in -(void)resize{ scaleX = ratioX0/ratioX; scaleY = ratioY0/ratioY; NSAffineTransform* tfm = [[NSAffineTransform alloc] init]; [tfm scaleXBy:scaleX yBy:scaleY]; temp = [tfm transformBezierPath:_path]; } The initial view was correct. Then dragging the window corner induced drawRect’s, which detected the changes and scaled the original _path each time; no cumulative errors. The path size tracked the view size correctly. Next I wanted to learn how to scale the whole view in a new project, not just the NSBezierPath. I was planning to later include other objects with the NSBezierPath and wanted them to be scaled, too. I used the same initialization and failed because of the bounds change between two passes, which I failed to anticipate. The first pass set the initial values. The second pass detected the change and scaled the view before the view appeared. -(void)resize{ scaleX = ratioX0/ratioX; scaleY = ratioY0/ratioY; NSAffineTransform* tfm = [[NSAffineTransform alloc] init]; [tfm scaleXBy:scaleX yBy:scaleY]; temp = [tfm transformBezierPath:_path]; } Thus the path in the initial view was quite different from the initial path, and dragging the corner of the window caused wildly incorrect scaling. My hope was that there might be a way of suppressing the second pass before display of the view. Now I know better and will figure out another way to initialize and track. Thank you for correcting me. Nick ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: drawRect runs twice, bounds are changed in between
On 15 Jan 2015, at 3:39 pm, N!K pu56ucl...@alumni.purdue.edu wrote: I’m trying to learn more about drawing. One stumbling block was getting an NSBezierPath to change size proportional to the window size when the corner is dragged. Per Graham Cox’s suggestion, the view size change can be detected in subsequent passes of drawRect by comparing ratioX = NSWidth ([_path bounds])/NSWidth(bounds); ratioY = NSHeight([_path bounds])/NSHeight(bounds); with their initial values, which were established in the one pass of drawRect before the view appeared. This wasn't my suggestion, exactly. Don't use -drawRect to establish anything - just use it to draw. Only draw. Only ever draw. My actual suggestion was to create your bezier path at some known size - I've used a size of 1 x 1 centred at 0,0 for example, then scale it to your needs *WHEN* you draw it, then discard the scaled version. That way you are proof against whatever size your view is, and when and how often it's called. You don't (and shouldn't) need a -resize method because you never store the results of it anyway. All that said, this is just toy code that shows you how you can apply scaling to a path - it isn't necessarily much use in real-world app. One problem with it for example is that it's possible to end up (if your view is zero-sized, as it can be when initialized) with div-by-zero errors that end up putting NaNs into the path's coordinates. Core Graphics (which has always tolerated that sort of thing historically) will, since 10.9, throw a fit and summarily abort your app. If you want to allow your view to zoom, rather than just display some content scaled, look into the relationship between the bounds and the frame of the view. Setting these different will cause zooming. If you want a slghtly more realistic way to place bezier path objects in a view, one approach could be to create an object that has a bezier path (maybe at a fixed size, such as 1 x 1), and also other states of it, such as its drawn size, angle and position from which you can create a transform. It's also convenient to include things such as stroke and fill colours. --Graham ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: drawRect runs twice, bounds are changed in between
On Jan 13, 2015, at 10:55 PM, Quincey Morris quinceymor...@rivergatesoftware.com wrote: On Jan 13, 2015, at 21:25 , N!K pu56ucl...@alumni.purdue.edu wrote: I have not been able to find a reason for this behavior. . I don’t know how to reveal the point between passes where bounds is actually changed. It does not happen in any other NSView projects of mine; drawRect runs only once in them The immediate reason is probably that the view’s size changed, which is not unlikely when the window is in the process of being displayed. The view may be resized for a “local” reason, such as the application of auto layout constraints, or for a “global” reason, such as the containing being resized and the change filtering down to subviews. Another possibility is that the view didn’t change size, but that (as an implementation detail of the Cocoa drawing system) it received two partial invalidations, and these weren’t coalesced in this case. I would like to prevent the second pass, or at least prevent the bounds change between passes. I don’t see any practical way to prevent ‘drawRect’ from being called again. Redundant ‘drawRect’ calls can occur any time during the view’s lifetime. This I didn’t realize, until you and Jens are explaining to me now. Are you implying that one bounds rect is “right” and one is “wrong”? No. The system draws the view correctly, as long as I don’t interfere by adding my attempt at initialization and scaling. If so, how do you know that, and why can’t you just make your code do nothing if the bounds are “wrong”? If the only criterion is that the *last* bounds rect is “right”, you’ve got a big problem, because there’s no such concept in the drawing system. If you’re hoping that someone can suggest a solution, you probably need to be more specific about what “right” and “wrong” mean. I’m reluctant to try restoring bounds to its first value. I appreciate Ken Thomases’ warning in a previous subject not to change bounds in drawRect. I’d say it wasn’t a warning, but rather an injunction to never, ever do that. Doing so is Wile E. Coyote stuff. I wish this had appeared in the Cocoa books I’ve read. On a lighter note, the Roadrunner cartoons are my favorites. Every blunder presents a classic engineering failure. :) ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: drawRect runs twice, bounds are changed in between
On Jan 13, 2015, at 10:50 PM, Jens Alfke j...@mooseyard.com wrote: On Jan 13, 2015, at 9:25 PM, N!K pu56ucl...@alumni.purdue.edu wrote: A breakpoint at the end of drawRect shows that it runs twice. After the second pass, the view appears, as it should. Between passes, bounds is changed somehow, as shown by NSLog at the start and end of drawRect. Since this will upset code that I will add later, I’d like to stop this. The view's being resized, probably as part of view layout. Ideally AppKit shouldn't draw the view before it gets to its final size, but maybe this is part of an animation, or maybe it's something that hasn't been optimized 100% in AppKit. In general, you should not make assumptions about when and how often -drawRect: will be called. That's up to AppKit. Your job is just to draw the view when you’re told to. OK. Cause is unknown (probably unknowable?) but part of Cocoa. Just because there was only one pass in other projects, I can’t depend on it. drawRect can happen anytime. You haven't said why the bounds change will upset your code; is the view being changed to the wrong size? That would be an actual problem, but it isn't related to being drawn multiple times. You'd need to look at the view constraints in your window to diagnose that. —Jens “Why” takes a little explaining. Thank you for your patience. I’m trying to learn more about drawing. One stumbling block was getting an NSBezierPath to change size proportional to the window size when the corner is dragged. Per Graham Cox’s suggestion, the view size change can be detected in subsequent passes of drawRect by comparing ratioX = NSWidth ([_path bounds])/NSWidth(bounds); ratioY = NSHeight([_path bounds])/NSHeight(bounds); with their initial values, which were established in the one pass of drawRect before the view appeared. This worked perfectly. I used the ratios in -(void)resize{ scaleX = ratioX0/ratioX; scaleY = ratioY0/ratioY; NSAffineTransform* tfm = [[NSAffineTransform alloc] init]; [tfm scaleXBy:scaleX yBy:scaleY]; temp = [tfm transformBezierPath:_path]; } The initial view was correct. Then dragging the window corner induced drawRect’s, which detected the changes and scaled the original _path each time; no cumulative errors. The path size tracked the view size correctly. Next I wanted to learn how to scale the whole view in a new project, not just the NSBezierPath. I was planning to later include other objects with the NSBezierPath and wanted them to be scaled, too. I used the same initialization and failed because of the bounds change between two passes, which I failed to anticipate. The first pass set the initial values. The second pass detected the change and scaled the view before the view appeared. -(void)resize{ scaleX = ratioX0/ratioX; scaleY = ratioY0/ratioY; NSAffineTransform* tfm = [[NSAffineTransform alloc] init]; [tfm scaleXBy:scaleX yBy:scaleY]; temp = [tfm transformBezierPath:_path]; } Thus the path in the initial view was quite different from the initial path, and dragging the corner of the window caused wildly incorrect scaling. My hope was that there might be a way of suppressing the second pass before display of the view. Now I know better and will figure out another way to initialize and track. Thank you for correcting me. Nick ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: drawRect runs twice, bounds are changed in between
On Jan 14, 2015, at 20:39 , N!K pu56ucl...@alumni.purdue.edu wrote: I’m trying to learn more about drawing. One stumbling block was getting an NSBezierPath to change size proportional to the window size when the corner is dragged. This is the wrong way to approach the problem. Scaling the bezier path itself is a bad idea, for two unrelated reasons: 1. Each time you apply a transform to the path, you’re doing floating point arithmetic, so you’re introducing errors. Possibly, in most circumstances, you won’t notice much, but the fact of accumulating error tells you that the approach is wrong. 2. A bezier path’s coordinates are dimensionless (that is, unit-less) numbers. They have no meaning in terms of points or pixels. They are *given* a meaning by the current transform matrix (CTM) of a context you draw the path into. When the CTM is the identity matrix, 1 unit in the Bezier path’s coordinates equals one point, but that’s a byproduct of the way the graphics system was designed — a mere convenience. Putting those two ideas together leads to a better approach. Create the bezier path once, relative to an arbitrary bounding rect — say 1000 x 1000. (But any rect would do.) When you need to draw the path, set the CTM of the context to scale 1000 x 1000 (the reference bounds) to the context’s width x height (the view bounds). Then just draw the original path and AppKit will scale the bezier path for you. This will work for all graphics in the view. Create all the elements relative to the same 1000 x 1000 bounds you used for the first bezier path, and everything will come out the correct size. It’s a little more complicated for “bitmap” graphics, because they intrinsically contain pixels. That may, but does not necessarily, mean that the bitmaps have an absolute size. This is important when you want to avoid having your bitmaps scaled when they’re drawn to the screen. However, in your case, you’re allowing the view to get resized to any size, which means bitmap scaling is going to happen most of the time. In this case, you can set your NSImage sizes (which are an abstract quantity) relative to the same 1000 x 1000 bounds you used before. Then, drawing NSImages will automatically scale the underlying bitmaps (regardless of their actual pixel dimensions) to the correct size for the view. The last point I want make is that if your goal is to scale *everything* in the view by the same amount, according to the size of the view, then you can use ‘setBoundsSize:’ to set the bounds size relative to the view frame size, which effectively causes everything in the view to be scaled automatically. If your ultimate goal is this uniform, bounds scaling is the easiest way to get there. The reference for all of this is the Cocoa Drawing Guide: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CocoaDrawingGuide/Introduction/Introduction.html https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CocoaDrawingGuide/Introduction/Introduction.html If you’re trying to gain expertise in custom drawing in custom views, you’re going to need to be familiar with pretty much everything in this document. P.S. ‘drawRect:’ never really had any relevance to what you’re trying to do. Even the NSView doesn’t really matter, except for telling you what absolute size to scale your graphics to. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: drawRect runs twice, bounds are changed in between
On Jan 13, 2015, at 9:25 PM, N!K pu56ucl...@alumni.purdue.edu wrote: A breakpoint at the end of drawRect shows that it runs twice. After the second pass, the view appears, as it should. Between passes, bounds is changed somehow, as shown by NSLog at the start and end of drawRect. Since this will upset code that I will add later, I’d like to stop this. The view's being resized, probably as part of view layout. Ideally AppKit shouldn't draw the view before it gets to its final size, but maybe this is part of an animation, or maybe it's something that hasn't been optimized 100% in AppKit. In general, you should not make assumptions about when and how often -drawRect: will be called. That's up to AppKit. Your job is just to draw the view when you're told to. You haven't said why the bounds change will upset your code; is the view being changed to the wrong size? That would be an actual problem, but it isn't related to being drawn multiple times. You'd need to look at the view constraints in your window to diagnose that. —Jens ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: drawRect runs twice, bounds are changed in between
On Jan 13, 2015, at 21:25 , N!K pu56ucl...@alumni.purdue.edu wrote: I have not been able to find a reason for this behavior. . I don’t know how to reveal the point between passes where bounds is actually changed. It does not happen in any other NSView projects of mine; drawRect runs only once in them The immediate reason is probably that the view’s size changed, which is not unlikely when the window is in the process of being displayed. The view may be resized for a “local” reason, such as the application of auto layout constraints, or for a “global” reason, such as the containing being resized and the change filtering down to subviews. Another possibility is that the view didn’t change size, but that (as an implementation detail of the Cocoa drawing system) it received two partial invalidations, and these weren’t coalesced in this case. I would like to prevent the second pass, or at least prevent the bounds change between passes. I don’t see any practical way to prevent ‘drawRect’ from being called again. Redundant ‘drawRect’ calls can occur any time during the view’s lifetime. Are you implying that one bounds rect is “right” and one is “wrong”? If so, how do you know that, and why can’t you just make your code do nothing if the bounds are “wrong”? If the only criterion is that the *last* bounds rect is “right”, you’ve got a big problem, because there’s no such concept in the drawing system. If you’re hoping that someone can suggest a solution, you probably need to be more specific about what “right” and “wrong” mean. I’m reluctant to try restoring bounds to its first value. I appreciate Ken Thomases’ warning in a previous subject not to change bounds in drawRect. I’d say it wasn’t a warning, but rather an injunction to never, ever do that. Doing so is Wile E. Coyote stuff. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com