如何在 Swift 中成功编译 NSClassFromString

How to successfully compile NSClassFromString in Swift

以下代码无法编译successfully.I还附上截图供参考!

func getXibViewWithClassNameString(classNameString:String)->AnyObject?{
    let projectName = Bundle.main.infoDictionary!["CFBundleExecutable"] as? String
    let MyClass:AnyClass = NSClassFromString(projectName! + "." + classNameString)!

    var viewArray:NSArray?
    var xibView:AnyClass?
    Bundle.main.loadNibNamed(classNameString, owner: nil, topLevelObjects: &viewArray)
    for viewInArray in viewArray ?? [] {
        if (viewInArray is MyClass){
        xibView = viewInArray as MyClass
        }
    }
    return xibView
}

screenshot for reference

您可以使用

进行测试
if viewInArray.isKind(of: MyClass) { ... } 

if viewInArray.isMember(of: MyClass) { ... } // strict class match

但我认为您不能将编译时不可用的 class 强制转换为 Swift。无论如何,您将无法直接调用它的任何方法。不过,您可以将其转换为某些 NSObject 子 class 并向其发送任意(未在编译时定义)消息。

这里的主要错误是您无法 asis 检查动态类型。您需要有一个在编译时已知的静态类型才能使用它。正如 pointum 所指出的,您需要在基础 NSObject 上使用 isKind(of:)isMember(of:) 。以下是我建议的做法:

func firstXibViewOfClass(named classNameString: String) -> NSView? {
    // Create an AnyClass object
    guard let projectName = Bundle.main.infoDictionary?["CFBundleExecutable"] as? String,
        let myClass = NSClassFromString(projectName + "." + classNameString)
        else {
            return nil
    }

    // Load the nib
    var topLevelObjects: NSArray?
    Bundle.main.loadNibNamed(classNameString, owner: nil, topLevelObjects: &topLevelObjects)

    // Convert it to NSObjects (since they all are going to be)
    guard let nsObjectArray = topLevelObjects as? [NSObject] else { return nil }

    // Find the first matching view and return it as an NSView if possible
    return nsObjectArray.first(where: {
        [=10=].isKind(of: myClass)  // Or isMember(of:) if you want to be strict
    }) as? NSView
}

不过,如果您不需要包含子类,您可能只想直接检查类名。这摆脱了所有 AnyClass 东西:

func firstXibViewOfClass(named classNameString: String) -> NSView? {
    // Load the nib
    var topLevelObjects: NSArray?
    Bundle.main.loadNibNamed(classNameString, owner: nil, topLevelObjects: &topLevelObjects)

    // Convert it to NSObjects (since they all are going to be)
    guard let nsObjectArray = topLevelObjects as? [NSObject] else { return nil }

    // Find the first matching view and return it as an NSView if possible
    return nsObjectArray.first(where: { [=11=].className == classNameString }) as? NSView
}

您当然可以 return AnyObject?,但该方法的名称表明您希望它是一个视图,因此您应该强制执行或重命名该方法。