我有一个嵌套类定义如下:
@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.B
0和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
放在应用程序的启动代码中。)