1

I'm trying to populate an NSOutlineView with Swift structs as its items. This works, except for the row(forItem:) method, which always returns -1. I've made sure my struct conforms to Equatable and I implemented an isEqual function. Still the NSOutlineView can not find the row for any item.

If I convert my struct to a class (not derived from NSObject), it all works. Even without conforming to Equatable or implementing any isEqual functions.

I thought classes and structs in Swift are basically the same except one being a reference type and the other a value type.

What do I need to implement to use Swift structs as items in an NSOutlineView?

Remco Poelstra
  • 859
  • 6
  • 20

3 Answers3

3

Someone posted a similar question on the Apple Developer Forum.

NSOutlineView doesn't use Equatable when identifying an item, it uses the reference pointer to the item. In Swift, structs are always passed by value (and not passed by reference) so the outline view will never recognize that the item you're passing is the same. Switching your struct to a class fixes the issue because Swift uses pass by reference for classes.

Unfortunately, there's no way to use Structs as items to work with NSOutlineView and you will need to use a Class.

Read this answer for more details about how Swift uses pass by reference vs. pass by value.

Community
  • 1
  • 1
Mel
  • 959
  • 5
  • 19
  • It’s a bi pt of a trap. It’ll work at first because if you import Foundation, structure can be automatically packed into `_SwiftValue`. You’ll get subtle bugs though, since those boxes will be created at different times, and they won’t have a stable reference identity, which is what `NSOutlineView` was relying on – Alexander Jul 18 '23 at 17:25
3

Release notes for macOS 10.14 point that if a Swift value type conforms to both Equatable and Hashable protocols, the NSOutlineView will successfully work with that value type.

But if you build against an older SDK, the value types won't work with the NSOutlineView indeed.

Vitalii Vashchenko
  • 1,777
  • 1
  • 13
  • 23
  • 1
    Link to the AppKit release notes: https://developer.apple.com/documentation/macos_release_notes/macos_mojave_10_14_release_notes/appkit_release_notes_for_macos_10_14 – David Nadoba Jan 28 '20 at 12:06
-1

You may override the method row(forItem item: Any?) in your subclass by simply looking all rows and returning the index of the equal ones.

Eldelshell
  • 6,683
  • 7
  • 44
  • 63
alazir
  • 1