How to conform to NSAccessibilityOutline?

I'm trying to conform to NSAccessibilityOutline like this:

class MyOutlineView: NSView, NSAccessibilityOutline {
    override func accessibilityLabel() -> String? {
        nil
    }
    func accessibilityRows() -> [NSAccessibilityRow]? {
        nil
    }
}

But that code gives this error:

Method 'accessibilityRows()' with Objective-C selector 'accessibilityRows' conflicts with method 'accessibilityRows()' from superclass 'NSView' with the same Objective-C selector

Any idea how I can work around this error?

Thanks,
Jesse

have you tried marking accessibilityRows() method with @objc?

@objc
func accessibilityRows() -> ...
1 Like

Thanks for the idea, but yeah I already tried that and still see the same error.

Sadly, I'm not sure that this is actually possible to do in pure Swift, given the definitions laid out in Obj-C.

When I start writing accessibilityRows(), I see two possible overloads to implement:

  • accessibilityRows() -> [NSAccessibilityRow]? comes from the NSAccessibilityTable protocol, which is inherited from NSAccessibilityOutline and is a requirement to fulfill the protocol
  • accessibilityRows() -> [Any]? comes from NSAccessibilityProtocol, which NSView adopts (and which you would need to override)

Because you inherit from both protocols, you'd need to override both methods to conform, but you can't because Swift is a bit more strict about Obj-C's rules than it is.

It also doesn't appear at first glance to be possible to get around using @_implements:

class MyView: NSView, NSAccessibilityOutline { // error: type 'MyView' does not conform to protocol 'NSAccessibilityTable'
    @_implements(NSAccessibilityTable, accessibilityRows)
    func myAccessibilityRows() -> [NSAccessibilityRow]? {
        nil
    }

    @objc
    override func accessibilityRows() -> [Any]? { // note: candidate has non-matching type '() -> [Any]?'
        nil
    }
}

Someone might be able to come up with another creative solution, but this is likely at least worth filing a Radar for.


In the meantime, it may be sufficient for your use-case to write an Objective-C base class which handles the NSAccessibilityOutline protocol implementation, with a concrete Swift subclass with the more "interesting" bits.

1 Like

Thanks for taking the time to dig into this.

I've submitted a radar. I haven't tried yet, but I guess I can workaround this issue by making my subclass Objective-c and then have that subclass call back into my swift code.

i wonder why are you doing this? don't see anything in the api that requires this conformance.

Good question, maybe that's where I'm going wrong. I am building an outline that visually is similar to NSOutlineView, but the implementation uses CALayer for all the different elements. I want to make it accessible. I figured the "correct" approach is to adopt the same protocol that NSOutlineView, but maybe in practice that's not really needed or much benefit?

won't subclassing NSOutlineView work for you?

I also encountered imported objc method signature problem. I end up using method swizzling to add such method dynamically.

I've submitted a radar.

What was the bug number?

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

1 Like

FB9680669

won't subclassing NSOutlineView work for you?

No, at least that's not the the approach that I want to take. My view is visually similar, but implementation is completely different. I might have also subclassed NSTextView for what I need. I did try subclassing (NSOutlineView and also NSTextView) at start of project, but wanted much more control/visibility into internals than I was able to get, so that's why I'm just subclassing NSView.

I recently got a suggested workaround:

As a workaround, you don’t need to conform to NSAccessibilityOutline. Instead, override accessibilityRows and also override accessibilityRole() to return the .outline role.