在swift中使用NSClassFromString实例化嵌套类



我有一个嵌套类定义如下:

@objc class A { 
@objc class B{
} 
}

并且我需要使用CCD_ 2来实例化CCD_。我可以为简单类A执行此操作,但当我附加到NSClassFromString参数.B字符串时,它只返回nil。

NSClassFromString("(appName).A") // works... 
NSClassFromString("(appName).A.B") //doesn't work.

我想,由于嵌套类在Objective-c中不可用,NSClassFromString只是不适用于嵌套类。。。在这种情况下,是否有其他方法可以从字符串初始化嵌套类?

//编辑

很好奇反函数NSStringFromClass在为标准类和嵌套类执行时如何返回不同的格式:

"myApp.A" <---- STANDARD CLASS (A)
"_TtCC15myApp13A6B" <----- NESTED CLASS (A.B) 

正如你所看到的,格式完全不同。那个_TtCC15是什么?为什么删除了"."?我认为将该格式的类传递给NSClassFromString应该可以。

我发现以下在操场上有效(Xcode 8.2/Swift 3):

// inheriting NSObject is required for `@objc`, at which point `@objc` is optional
class A: NSObject {
class B: NSObject {
override var description: String { return "foo" }
}
}
let str = NSStringFromClass(A.B.self)
guard let anyClass = NSClassFromString(str)
else { fatalError("no class") }
// cast to a type that defines `init()` so we can instantiate
guard let nsClass = anyClass as? NSObject.Type 
else { fatalError("class isn't NSObject") }
// call `.init()`, not `nsClass()`; constructor syntax is for static types only
let instance = nsClass.init() 
print(instance) // -> "foo"

奇怪的类"name"字符串是因为ObjC运行时不理解嵌套类(或Swift可以定义但ObjC不能定义的其他类型)——在Swift本身中,这种混乱的名称是如何唯一定义类型、函数等的。(例如,名称损毁也是函数重载的工作方式:A.B0和func foo(num: Int) -> Bool在内部有不同的损毁名称。)

桥接机制仍然可以动态解析一个类,给定其被正确篡改的Swift名称,但Swift名称篡改是一个实现细节,可能会发生更改。(至少在Swift 4锁定ABI之前。)因此,在同一程序中将NSStringFromClass的结果传递给NSClassFromString是安全的,但在测试中记录一次损坏的名称是不安全的,将损坏的名称作为字符串文字或资源发送到应用程序中,并期望它稍后与NSClassFromString一起使用。

相反,如果您希望您的嵌套类(或任何其他Swift定义的类)有一个可靠的已知名称用于ObjC运行时,请给它一个@objc(name)(如文档中所述):

@objc class A: NSObject {
@objc(A_B) class B: NSObject { /*...*/ }
}
guard let anyClass = NSClassFromString("A_B")
else { fatalError("no class") }

(请注意,这个代码段不会自己运行——类A.B必须在进程中的某个地方至少引用一次,才能在ObjC运行时中注册。这可以简单到将let t = A.B.self放在应用程序的启动代码中。)

最新更新