Bug? Can't implement optional protocol methods on subclass of generic superclass conforming to ObjC protocol

The title's a mouthful, so let me elaborate.

Suppose you have the following set up:

import Foundation

import Foundation

@objc protocol ObjCProtocol {
	@objc optional func optionalFunc1()
	@objc optional func optionalFunc2()
}

class SuperClass<T>: ObjCProtocol {
	func optionalFunc1() {
		print("SuperClass.optionalFunc1()")
	}
}

class SubClass: SuperClass<Void> {
	func optionalFunc2() {
		print("SuperClass.optionalFunc2()")
	}
}

let s1: ObjCProtocol = SuperClass<Void>()
s1.optionalFunc1!()

let s2: ObjCProtocol = SubClass()
s2.optionalFunc1!()
s2.optionalFunc2!()

optionalFunc2 looks like it's an implementation of the optional func optionalFunc2() requirement of ObjCProtocol. However, when you try it, it explodes:

SuperClass.optionalFunc1()
SuperClass.optionalFunc1()
objc[68263]: -[main.SubClass optionalFunc2]: unrecognized selector sent to instance 0x7ff13fc05410 (no message forward handler is installed)

Interestingly, all this works if you make SuperClass non-generic:

import Foundation

@objc protocol ObjCProtocol {
	@objc optional func optionalFunc1()
	@objc optional func optionalFunc2()
}

class SuperClass: ObjCProtocol {
	func optionalFunc1() {
		print("SuperClass.optionalFunc1()")
	}
}

class SubClass: SuperClass {
	func optionalFunc2() {
		print("SuperClass.optionalFunc2()")
	}
}

// and from here... it works.
let s1: ObjCProtocol = SuperClass()
s1.optionalFunc1!()

let s2: ObjCProtocol = SubClass()
s2.optionalFunc1!()
s2.optionalFunc2!()

Background

Here's the background of how I stumbled into this issue, in case anyone's interested. Above is a minimal replication of my issue, which actually has to do with NSOutlineViewDelegate. I have Swift class declared like so:

class OutlineViewDelegate<Model: NSObject>: NSObject, NSOutlineViewDelegate

It has an array of OutlineViewColumnConfiguration<Model> member. Each OutlineViewColumnConfiguration contains a render function, which takes a NSTableCellView and Model. This implementation of delegate uses these closures to prepare the cells, rather than using a massive switch statement in outlineView(_:viewFor:item:).

I then have a subclass of that class, which wants to implement some less-abstract behavior of NSOutlineViewDelegate (e.g. responding to selections).

That sounds like SR-9479; fortunately, it's a sufficient workaround to mark the methods @objc yourself (possibly with an explicit selector).

1 Like

Ah yes, that looks like an exact match. Specifying @objc explicitly solved my problem. Thanks Jordan!