我有一个像这样定义的嵌套类:
var showing = 'F';
temp.addEventListener('click', degreeToF);
function degreeToF() {
if(showing === 'F'){
// convert to C
showing = 'C';
const f = (manchester.current.temp_c - 32 ) * 5/9;
temp.innerHTML = f.toFixed(0) + '<span class="degrees"> c </span>';
} else {
// convert to
showing = 'F';
const f = manchester.current.temp_c * 1.8 + 32;
temp.innerHTML = f.toFixed(0) + '<span class="degrees"> f </span>';
}
}
我需要使用@objc class A {
@objc class B{
}
}
来实例化A.B
。我能够为简单的类NSClassFromString
执行此操作,但当我将A
参数附加到NSClassFromString
字符串时,它只返回nil。
.B
我认为由于嵌套类在Objective-c中不可用,NSClassFromString("\(appName).A") // works...
NSClassFromString("\(appName).A.B") //doesn't work.
只是不适用于嵌套类...在这种情况下,有另一种方法从字符串初始化嵌套类?
//编辑
很奇怪逆函数NSClassFromString
在为标准类和嵌套类执行时如何返回不同的格式:
NSStringFromClass
正如您所看到的,格式完全不同。什么是"myApp.A" <---- STANDARD CLASS (A)
"_TtCC15myApp13A6B" <----- NESTED CLASS (A.B)
?为什么&#34;。&#34;已被删除?我认为将该格式的类传递给_TtCC15
应该可以。
答案 0 :(得分:2)
我发现以下内容适用于游乐场(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本身内,这样的错位名称是如何类型的,函数等得到唯一定义。 (例如,名称修改也是函数重载的工作方式:func foo()
和func foo(num: Int) -> Bool
内部具有不同的损坏名称。)
桥接机制仍然可以动态解析一个类,因为它有适当的错误Swift名称,但Swift名称修改是一个实现细节,可能会发生变化。 (至少在Swift 4锁定ABI之前。)因此,在同一程序中将NSStringFromClass
的结果传递给NSClassFromString
是安全的,但在测试中记录错误的名称是不安全的(例如) ,将名称错误地作为字符串文字或资源添加到您的应用中,并期望它稍后与NSClassFromString
一起使用。
相反,如果您希望嵌套类(或任何其他Swift定义的类)具有可靠的已知名称以供ObjC运行时使用,请为其指定@objc(name)
(如the docs中所述) ):
@objc class A: NSObject {
@objc(A_B) class B: NSObject { /*...*/ }
}
guard let anyClass = NSClassFromString("A_B")
else { fatalError("no class") }
(注意这个片段本身不会运行 - 为了在ObjC运行时注册,必须至少在进程的某个地方引用类A.B
。这可能就像放入一样简单在应用的启动代码中的某个地方let t = A.B.self
。)