NSOutlineView, reloading items, and the expansion state

Apple, Cocoa, Other Stuff

NSOutlineView requires all of the items in it to be pointer unique. If they are not, strange things happen. However, they can be equal (meaning [NSObject isEqual] may return YES).

However, there is a small exception to that rule. If you do a reload, the expansion state of items will be preserved. This expansion state is done by placing the current expanded items into an NSMutableSet. After a reload happens, if an item is in that set it is shown expanded.

What does this mean? Well, to see if an item should be expanded or not, it is looked up in the set. This is done via the item’s hashcode and an isEqual comparision. Ahh ha! NSOutlineView is doing some non-pointer unique things here. This means you could potentially switch out items during a reload, and they would still appear expanded after the reload (as long as they have the same hashcode and are isEqual). Another nasty side effect: any items which mutate their hashtable will not appear expanded after a reload! For instance, if you modify an NSDictionary, its hash code will change. Take this point into consideration: the objects you put into an NSOutlineView are NSMutableDictionaries. You do a reload, and after the reload you add a child to one of the items via a key in the NSDictionary. Therefore, the NSMutableDictionary now has a different hashcode, and it will no longer appear expanded! The easy way to work around this is to use a non-mutable object in the outlineview (such as your own object, which might have a dictionary inside of it to keep track of things). Just a neat tip, for those who care or run into this.

Tags:


Subscribe
Notify of
guest

6 Comments
Inline Feedbacks
View all comments
Jerry Krinock

Thank you for explaining this.

Bonifacius

Great article. I am just sad I dont know how to reply properly, though, since I want to show my appreciation like many other.

george

I assume overriding isEqual: and hash: for the outline item class would be a Very Bad Ideaâ„¢ as it would screw up other things?

george

I was thinking specifically for a Core Data entity. I did a quick test and I’m still getting stray items collapsing. However, this is happening when I call rearrangeObjects on an NSTreeController to refresh the NSOutlineView so perhaps that’s a completely different case than what you’ve described for reloadData. I know Core Data + NSTreeController can complicate things quite a bit, so perhaps I’ll just end up saving expansion state in the model and restoring manually.

Thanks.

Subscribe to new posts:

You'll get an email whenever a I publish a new post to my blog and nothing more. -- Corbin

As an Amazon Associate I earn from qualifying purchases.

(c) 2008-2024 Corbin Dunn

Privacy Policy

Subscribe to RSS feeds for entries.

70 queries. 0.169 seconds.

Log in