Swift 4 Objective-C Runtime and casting to NSObjectProtocol
Asked Answered
C

2

6

In Swift 3, I had a snipped of code that called into Objective-C runtime to check if a certain class is present.

guard let managerClass = NSClassFromString("ASIdentifierManager") as? NSObjectProtocol else {
    return nil
}

This returns AnyClass instance and it is castable to NSObjectProtocol - so I could call methods like responds and perform to work with selectors.

In Swift 4, this still works at runtime, but will emit a warning:

Cast from 'AnyClass?' (aka 'Optional') to unrelated type 'NSObjectProtocol' always fails

Oddly it still works, but I am worried a certain Swift version will kill the code.

What is the proper way to get rid of this warning? To what should I cast the object, to be able to perform selectors on it dynamically?

Cho answered 30/8, 2017 at 10:10 Comment(2)
I think you should cast to NSObjectProtocol.Type.Zygote
Incorrect, as I am not interested in NSObjectProtocol.Type, but rather it is an instance of NSObjectProtocol.Cho
M
9

Looks like you need to cast from AnyObject.Type to AnyObject first to convince the compiler that you're talking about an instance (albeit an instance of a metaclass, as you know):

    guard
        let klass = NSClassFromString("ASIdentifierManager"),
        let managerClass = klass as AnyObject as? NSObjectProtocol else
    {
        return nil
    }

I'm not sure whether this should be considered a compiler bug or not. I'd bet not, and that there's some Swiftian reason that NSObjectProtocol does not apply to ObjC type objects when in a Swift context.

Medicate answered 12/9, 2017 at 0:59 Comment(0)
Z
0

You should cast to NSObjectProtocol.Type:

guard let managerClass = NSClassFromString("ASIdentifierManager") as? NSObjectProtocol.Type else {
    return nil
}
Zygote answered 30/8, 2017 at 11:14 Comment(7)
This is incorrect. While you can do this cast without the warning, you can no longer use responds and perform methods, as this is a type, not an instance anymore.Cho
This is correct. NSClassFromString <- returns class not an instance. If you want instance you have to create it.Zygote
In Objective-C type class also is an instance of class class. Each class instance has a meta class. So it is incorrect. I know it is confusing, but it is effectively how Objective-C runtime works.Cho
@Cho You want to call class method through perform selector?Zygote
Exactly, yes! The code I had worked in Swift 3 and is semantically correct. The code actually still works, but will emit warning described in the question.Cho
Did you actually try my code? It should work I guessZygote
Yes, it doesn't work, because there's no way to call any Objective-C runtime methods on that meta type.Cho

© 2022 - 2024 — McMap. All rights reserved.