> On 9 Mar 2017, at 01:49, Quincey Morris <quinceymor...@rivergatesoftware.com> 
> wrote:
> 
> So, the correct answer to your original question, I think, is that if your 
> model data has changed in such a way that the representation in custom views 
> no longer reflects the data, then you should set “needsDisplay” on *every* 
> custom subview that uses “draw(_:)”.
> 
> If you just need your changed view to be re-composited with the same subview 
> contents as previously, then you don’t need to set “needsDisplay” on the 
> subviews, just the parent view.

OK - that disagrees with Ben’s conclusion:

"Thus, it seems to follow that so long a custom view's display() calls super, 
then all of its subviews should also be drawn when its needsDisplay is true.”

But maybe it is covered by the “as necessary” clause in Apple’s documentation:

display(): "Displays the view and all its subviews if possible, invoking each 
of the NSView methods lockFocus(), draw(_:), and unlockFocus() as necessary.”

I have a custom view that has two custom subviews, and is a subclass of a more 
general custom view. The code that tells the general (superclass) view that it 
needs to be redrawn shouldn’t have to know which kind of (subclass) view it is 
dealing with. So it would be necessary for the subclass view to override 
needsDisplay with an observer that sets needDisplay to be true for its subviews:

override var needsDisplay: Bool
{
        didSet
        {
                for view in subviews
                {
                        view.needsDisplay = needsDisplay
                }
        }
}

Currently, I don’t actually need to do this because I’m not trying to use 
layer-backed views (that happened accidentally through a bug or unexpected 
behaviour in Interface Builder), but the fact that Apple is unclear about how 
needsDisplay affects subviews means that I probably should do this in case they 
introduce new drawing optimisations in future versions of macOS.

The other puzzle in all this is why it should be the case that setting 
needsDisplay to be true on a layer-backed view actually doesn’t set it to be 
true:

> One other strange behaviour with the problem xib occurred when I added some 
> debugging code to try and find out why the subview wasn’t being redrawn:
> 
>       view.needsDisplay = true
>       print("view.needsDisplay: \(view.needsDisplay)”)
> 
> and this consistently printed “ view.needsDisplay: false” after 
> view.needsDisplay had been set to true. Despite this, “draw” (= drawRect in 
> ObjC) was being called for “view” - but not for view’s subviews.

Before I discovered that IB had changed one of my views to be layer-backed, I 
tried using the didSet observer to pass on needsDisplay to subviews and found 
that it was setting the value to be false for subviews when I had set it to be 
true for the superview (that’s why I added the debugging code above).

So it seems that for layer-backed views, setting needsDisplay does cause the 
view to be redrawn - but the value is never actually set. If I needed to work 
with layer-backed views, it might be possible to get around this by overriding 
willSet instead of didSet.

I think NSView needs a “Redraws subviews” property (similar to “Autoresizes 
subviews”) that will take away the guesswork and hackery that we currently need 
to use in order to get some kind of consistent behaviour.

Jeremy


_______________________________________________

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

Reply via email to