@objc functions in protocol extensions

I'm trying to make a typed wrapper for NSOutlineViewDataSource. So far I have this:

protocol TypedNSOutlineViewDataSource: NSOutlineViewDataSource {
	associatedtype ItemType

	func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: ItemType?) -> Int
	func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: ItemType?) -> ItemType
	func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: ItemType) -> Bool
}

extension TypedNSOutlineViewDataSource {
	func outlineView(_ view: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
		return outlineView(view, numberOfChildrenOfItem: item as! ItemType?)
	}
	func outlineView(_ view: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
		return outlineView(view, child: index, ofItem: item as! ItemType?)
	}
	func outlineView(_ view: NSOutlineView, isItemExpandable item: Any) -> Bool {
		return outlineView(view, isItemExpandable: item as! ItemType)
	}
}

But when I try to make something conform to it, I get a bunch of warnings: Non-'@objc' method 'outlineView(_:child:ofItem:)' does not satisfy optional requirement of '@objc' protocol 'NSOutlineViewDataSource'

Applying the fix-it and adding @objc to the functions gets a new error: @objc can only be used with members of classes, @objc protocols, and concrete extensions of classes

Is there anything I can do here or am I stuck throwing Any around?

1 Like

Unfortunately you can't extend Objective-C protocols, and you can't define Objective-C members outside the class itself. If you want to deal with the full Type, the closest thing I can think of is with a Generic parent Class that you subclass. It's definitely messier, but that tends to be how it works going between the two languages. especially with the older AppKit APIs.

e.g.

class ObjectiveCClass<ItemType>: NSObject, NSOutlineViewDataSource {

    func outlineView(_ view: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
        return outlineView(view, numberOfChildrenOfItem: item as! ItemType?)
    }
    func outlineView(_ view: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
        return outlineView(view, child: index, ofItem: item as! ItemType?)
    }
    func outlineView(_ view: NSOutlineView, isItemExpandable item: Any) -> Bool {
        return outlineView(view, isItemExpandable: item as! ItemType)
    }

    func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: ItemType?) -> Int {
        assert(false, "Should be implemented by subclass")
        return 0
    }
    func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: ItemType?) -> ItemType {
        assert(false, "Should be implemented by subclass")
        return item!
    }
    func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: ItemType) -> Bool {
        assert(false, "Should be implemented by subclass")
        return false
    }

}

class SubClass: ObjectiveCClass<String> {

    override func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: String?) -> Int {
        // Your Implementation
    }
    override func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: String?) -> String {
        // Your Implementation
    }
    override func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: String) -> Bool {
        // Your Implementation
    }
}
1 Like
Terms of Service

Privacy Policy

Cookie Policy