Why can't @objc dynamic applied to property of generic type that is an NSObject?

From what little I understand, generic classes are specialized at compile time.

I wonder then why does this not work:

class Muppet<Color>: NSObject where Color: NSObject {
    @objc dynamic var color: Color?
}

I get the classic Property cannot be marked @objc because its type cannot be represented in Objective-C

IIUC the @objc dynamic ensures that at runtime the correct KVO methods are emitted, but since the variable color is guaranteed to be an Objective-C class, I don't quite understand why this is not possible.

1 Like

Generic classes are not specialized at compile time in Swift (except as an optimization), but even without that you're right that it would be possible to be compatible with the Objective-C runtime here. The problem is that @objc is used both for run-time Objective-C interop and compile-time Objective-C interop (the generated header), and so the restrictions are pretty limiting.

Now, in this particular case, the class is generic, and so there's no way it could be exposed to Objective-C at compile-time. I could see us deciding to lift some of the restrictions because of that, but I'd want us to think about it, so that we don't create a situation where people start saying "@objc behaves in different ways based on the context and there doesn't seem to be any consistent rule".

3 Likes

Note that @objc is permitted on members of generic classes; as long as their types don't mention generic parameters.

1 Like

I understand that, but it would be so much fun if that wasn't the case if the generic argument is an Objective-C class.

It would make it very convenient to create generic subclasses of AppKit components. Now I can use type erasers to do that when using closures or callbacks on those, but I can't observe a selected object property nicely using KVO.

Something along the lines of

final class EntityPopUpButton<Entity: NSObject>: NSPopUpButton {
@objc dynamic var selectedEntity: Entity?
// …
}

:cry:

Has there been any progress on this? The ability to use generics from Swift to Objective-C that are subclasses of NSObject would be extremely useful for me.

For example one project I am working on is an app that is a mix of Objective-C and Swift. We would like to take advantage of generics on the swift side, but currently we can't since we need to maintain compatibility with the Objective-C parts of the code base.

I think it's unlikely that progress will be made on this front. It would mean adding support for generics to Objective-C which is likely a huge effort with large impact on Objective-C itself..

Would Objective-C really need to fully support generics. I might be missing something but lets say I have a generic class that looks like this:

class MyGenericClass <Type: NSObject> : NSObject {
    var value: Type
        
    init(value: Type) {
        self.value = value
    }
        
    func getValue() -> Type {
        return value
    }
}

Now in another Swift class I would like to exposure it as so:

@objc let testMy = MyGenericClass<NSString>(value: "test")

Couldn't the compiler know that "value" and "getValue()" will always return type "NSString" which is Objective-C compatible?

Terms of Service

Privacy Policy

Cookie Policy