Any reason of "@objc is not supported within extensions of generic classes." ?

I was trying to implement a final class to conform NSCopying by extension.
List<T> was a class in Realm object database.

final class List<T>

My implementation:

extension List:NSCopying {
    public func copy(with zone: NSZone? = nil) -> Any {
        ...
    }
}

I got an error called "@objc is not supported within extensions of generic
classes.". Any idea why there is a limitation of this? Thanks.

Zhaoxin

1 Like

The way @objc methods are added in an extension is by using Objective-C categories. With a generic class, though, there's no Class object to attach the category metadata to—it's all created dynamically at runtime.

We could potentially support this some day, but it would take some thought, and we'd have to be careful not to drastically slow down the cost of instantiating new concrete types from a heavily-extended generic class.

Jordan

···

On Aug 24, 2016, at 7:23, Zhao Xin via swift-users <swift-users@swift.org> wrote:

I was trying to implement a final class to conform NSCopying by extension. List<T> was a class in Realm object database.

final class List<T>

My implementation:

extension List:NSCopying {
    public func copy(with zone: NSZone? = nil) -> Any {
        ...
    }
}

I got an error called "@objc is not supported within extensions of generic classes.". Any idea why there is a limitation of this? Thanks.

Zhaoxin
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

3 Likes

Thank you, Jordan.

Zhaoxin

···

On Thu, Aug 25, 2016 at 1:15 AM, Jordan Rose <jordan_rose@apple.com> wrote:

The way @objc methods are added in an extension is by using Objective-C
categories. With a generic class, though, there's no Class object to attach
the category metadata to—it's all created dynamically at runtime.

We could potentially support this some day, but it would take some
thought, and we'd have to be careful not to drastically slow down the cost
of instantiating new concrete types from a heavily-extended generic class.

Jordan

On Aug 24, 2016, at 7:23, Zhao Xin via swift-users <swift-users@swift.org> > wrote:

I was trying to implement a final class to conform NSCopying by extension.
List<T> was a class in Realm object database.

final class List<T>

My implementation:

extension List:NSCopying {
    public func copy(with zone: NSZone? = nil) -> Any {
        ...
    }
}

I got an error called "@objc is not supported within extensions of generic
classes.". Any idea why there is a limitation of this? Thanks.

Zhaoxin
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

@jrose Could you please elaborate a little bit more on your answer?
I mean as far as I know methods in Categories are also a dynamic and are prepended to the list of the class method at run time (correct me if I am wrong)

I am not sure I understand it, does it means that generic classes are created dynamically?
If so, I am not sure why its not possible to attach/prepend categories method to them

In the Objective-C ABI, a category references type metadata for a specific class that it is attached to. In Swift, instantiations of a generic class are lazily constructed at runtime for each unique set of type arguments. So we can't emit the category statically (there isn't one fixed class to attach it to), so we would need some runtime machinery to track Objective-C categories for generic Swift classes, and attach them to each instantiation of the generic class. It's not impossible, but a lot of work for a rare edge case.

For similar reasons, @objc members cannot appear in protocol extensions either.

1 Like

@Slava_Pestov thanks a lot for your input.
So does it mean from you answer that swizzeling in generic class (although its an obj c class) wont be possible.
I came across this thread while trying too swizzle UIHostingViewController viewDidload method but I was always stuck with 'swizzleViewDidLoad' is marked @objc dynamic in the Extension for UIHostingViewController (I tried also the new features api @_dynamicReplacement( **for** : viewDidAppear(_:)) but no luck).
@Slava_Pestov maybe you could suggest alternative approach on how can I achieve what I described above, (I can swizzle UIVieController but then I don't have access to UIHostingController swift properties, as for casting I need the exact generic type)

Sorry for bringing up this old thread. Is there still no solution for it?

I try to swizzle a function of an UIHostingController.

Swizzling Apple-provided methods is not recommended cause they can always change out from under you, or rely on behavior you’re not perfectly preserving.

…but that out of the way, I think you could swizzle a method on a specific generic instantiation:

  1. Make a non-@ObjC method that calls the original implementation but also does your additional work.
  2. Use imp_implementationWithBlock to call that method in a block, converted to an IMP.
  3. Install that IMP onto a particular UIHostingController<Whatever>, saving the old IMP for your step-1 method to call.
2 Likes