Missing children in NSTreeController/NSOutlineView

  • Hi all,

    I have as follows in Interface builder:

    - A superclass with a @property NSOrderedSet *properties containing zero or more instances of objects, as well as some normal string properties. All the objects inherit from the superclass.

    - An NSTreeController whose content object is bound to the selection of an NSArrayController. The NSTreeController is configured with the children key path "properties"

    - An NSOutlineView whose content is bound to my tree controller's arrangedObjects. The outline view has two columns, each bound to a string property on arrangedObjects.

    When I run my app, the outline view populates and changes its contents when I change the selection of the array controller. The columns show the string properties as expected.

    However, no children are displayed and there is no disclosure triangle. I have verified with breakpoints that the tree controller does access my "properties" and that a set is returned with contents of the right objects. Likewise, changing the children key path to a non-existing property will yield a KVO-compliance exception.

    I've read through the docs and spent some time googling, but nothing I've found has suggested a reason for the children to be missing.

    What am I doing wrong?

    Regards,

    Mikkel
  • On May 14, 2012, at 00:40 , Mikkel Eide Eriksen wrote:

    > - An NSTreeController whose content object is bound to the selection of an NSArrayController. The NSTreeController is configured with the children key path "properties"

    1. Check that you have the correct configuration for the count key and/or the leaf key.

    2. Check the KVO compliance of whichever of these keys you use. For example, a leaf key like this:

    - (BOOL) isLeaf {
      return self.properties.count > 0;
    }

    *isn't* KVO compliant.
  • Thanks,

    I don't currently have leaf/count configured. They are empty in IB - my impression was that they were optional and for performace?

    Mikkel

    On 14/05/2012, at 10.06, Quincey Morris <quinceymorris...> wrote:

    > On May 14, 2012, at 00:40 , Mikkel Eide Eriksen wrote:
    >
    >> - An NSTreeController whose content object is bound to the selection of an NSArrayController. The NSTreeController is configured with the children key path "properties"
    >
    > 1. Check that you have the correct configuration for the count key and/or the leaf key.
    >
    > 2. Check the KVO compliance of whichever of these keys you use. For example, a leaf key like this:
    >
    > - (BOOL) isLeaf {
    > return self.properties.count > 0;
    > }
    >
    > *isn't* KVO compliant.
    >
    >
  • On May 14, 2012, at 01:13 , Mikkel Eide Eriksen wrote:

    > I don't currently have leaf/count configured. They are empty in IB - my impression was that they were optional and for performance?

    One or other of them is used, though I believe that the count key defaults to "count" if not specified in IB.

    It's also possible that your "properties" property isn't KVO compliant.
  • On May 14, 2012, at 1:06 AM, Quincey Morris <quinceymorris...> wrote:

    > 2. Check the KVO compliance of whichever of these keys you use. For example, a leaf key like this:
    >
    > - (BOOL) isLeaf {
    > return self.properties.count > 0;
    > }
    >
    > *isn't* KVO compliant.

    Hmm? As long as you return a set containing "properties" from +keyPathsAffectingIsLeaf, and your class is KVO compliant for "properties", this should also be KVO compliant.

    --Kyle Sluder
  • There it was! My "properties" property is an NSOrderedSet. After some more time in the debugger, I found out that the tree controller gets the object at children key path, and checks whether it's an NSSet or an NSArray. NSOrderedSet is neither, it inherits directly from NSObject and that appears to be the problem.

    As a quick hack to test this, I made a "propertiesSet" property that just returns [[self properties] set] and the children now show up as expected.

    I guess I'll have to refactor some things.

    Mikkel
  • On May 14, 2012, at 10:40 AM, Kyle Sluder wrote:

    > On May 14, 2012, at 1:06 AM, Quincey Morris <quinceymorris...> wrote:
    >
    >> 2. Check the KVO compliance of whichever of these keys you use. For example, a leaf key like this:
    >>
    >> - (BOOL) isLeaf {
    >> return self.properties.count > 0;
    >> }
    >>
    >> *isn't* KVO compliant.
    >
    > Hmm? As long as you return a set containing "properties" from +keyPathsAffectingIsLeaf, and your class is KVO compliant for "properties", this should also be KVO compliant.

    Well, yes, but that's a big "as long as". ;)  I mean, it's not hard to do that, but it's not something that most developers think of spontaneously.

    Anyway, Quincey's point was that that isLeaf getter _in isolation_ doesn't make for a KVO-compliant property.  It is a common mistake.

    Cheers,
    Ken
  • On May 14, 2012, at 08:40 , Kyle Sluder wrote:

    > On May 14, 2012, at 1:06 AM, Quincey Morris <quinceymorris...> wrote:
    >
    >> 2. Check the KVO compliance of whichever of these keys you use. For example, a leaf key like this:
    >>
    >> - (BOOL) isLeaf {
    >> return self.properties.count > 0;
    >> }
    >>
    >> *isn't* KVO compliant.
    >
    > Hmm? As long as you return a set containing "properties" from +keyPathsAffectingIsLeaf, and your class is KVO compliant for "properties", this should also be KVO compliant.

    That was my point, the "naked" isLeaf method isn't KVO compliant unless you supplement it with something like keyPathsAffectingIsLeaf.

    Note that the set should return "properties.count" (not "properties"), and the class should be KVO compliant for both "properties" AND "count".
  • On May 14, 2012, at 9:02 AM, Quincey Morris <quinceymorris...> wrote:

    > On May 14, 2012, at 08:40 , Kyle Sluder wrote:
    >
    >> On May 14, 2012, at 1:06 AM, Quincey Morris <quinceymorris...> wrote:
    >>
    >>> 2. Check the KVO compliance of whichever of these keys you use. For example, a leaf key like this:
    >>>
    >>> - (BOOL) isLeaf {
    >>> return self.properties.count > 0;
    >>> }
    >>>
    >>> *isn't* KVO compliant.
    >>
    >> Hmm? As long as you return a set containing "properties" from +keyPathsAffectingIsLeaf, and your class is KVO compliant for "properties", this should also be KVO compliant.
    >
    > That was my point, the "naked" isLeaf method isn't KVO compliant unless you supplement it with something like keyPathsAffectingIsLeaf.
    >
    > Note that the set should return "properties.count" (not "properties"), and the class should be KVO compliant for both "properties" AND "count".

    If properties is a collection type—NSArray, NSSet, or (as I understand it) NSOrderedSet)—then it is necessary and sufficient to only return "properties." These classes are not KVO-compliant for the key "count," and any KVO-compliant change to the "properties" key will generate the correct KVO notifications.

    --Kyle Sluder
  • On May 14, 2012, at 09:07 , Kyle Sluder wrote:

    > If properties is a collection type—NSArray, NSSet, or (as I understand it) NSOrderedSet)—then it is necessary and sufficient to only return "properties." These classes are not KVO-compliant for the key "count," and any KVO-compliant change to the "properties" key will generate the correct KVO notifications.

    Oh, tunnel vision on my part. For those classes, the count can't change unless the collection changes.
previous month may 2012 next month
MTWTFSS
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
Go to today