在Swift中获取类的名称非常容易,如下所示:
import Foundation
class Gen<T> {
init() { }
}
func printName(obj: AnyObject) {
dump(NSStringFromClass(obj.dynamicType))
}
let a: Gen<String> = Gen()
let b: Gen<Int> = Gen()
printName(a)
printName(b)
但是,如果运行上述代码两次,则不会产生相同的结果。
那么,是否有一种稳定的方式来实现printName
(获取专门的泛型类名)?也就是说,代码的多次运行会为同一个类打印相同的字符串吗?
我正在使用最新的Xcode测试版。
一些额外要求:
printName
的类数量很高。发布于 2015-02-03 23:55:14
从Xcode 6.3 beta 1开始的新版本
好消息!从6.3开始,您可以:
toString(Gen<Int>())
然后打印出来:Gen<Swift.Int>
旧答案:
如果可以将范围缩小为T: AnyObject,则可以按以下方式实现:
class Gen<T: AnyObject> {
var className: String {
return "Gen<\(NSStringFromClass(T.self))>"
}
}
发布于 2015-02-02 21:59:26
很抱歉让人失望,但这似乎是不可能的,除非您积极地编写一个新的编译器。
看看这个source。作者很好地描述了它:Note that the isa pointer of the two objects is not identical, even though both are an instance of WrapperClass. Evidently, a specialization of a generic class is a separate class at runtime.
我还在玩@objc
,但这只是改变类的名称空间,但显然对类名没有影响。
发布于 2015-02-06 12:56:43
据我所知,这将打印Gen
,并适用于任何类:
class Gen<T> {
init() { }
}
func printName(obj: AnyObject) {
let desc = reflect(obj).summary
let scanner = NSScanner(string: desc)
var name: NSString?
scanner.scanUpToString(".", intoString: nil)
scanner.scanString(".", intoString: nil)
scanner.scanUpToString("", intoString: &name)
if let n = name {
println(n)
}
}
但是,它不会给您提供专门的类型--例如Gen<String>
或Gen<Int>
--而且我现在只在在线REPL上测试它,因此结果可能在项目或游乐场内有所不同。
您需要它来提供专门的类型,还是类名足够?
编辑:我结合了@relejo的答案和我的答案,给出了专门的类型,使用了他建议的协议和计算属性:
protocol GenericClassName {
var className: String { get }
}
class Gen<T: AnyObject>: GenericClassName {
init() { }
var className: String {
return NSStringFromClass(T.self)
}
}
func printName<U: GenericClassName>(obj: U) {
let desc = reflect(obj).summary
let scanner = NSScanner(string: desc)
var name: NSString?
scanner.scanUpToString(".", intoString: nil)
scanner.scanString(".", intoString: nil)
scanner.scanUpToString("", intoString: &name)
if let n = name {
println(n + "<\(obj.className)>")
}
}
let gen1 = Gen<NSString>()
let gen2 = Gen<NSNumber>()
printName(gen1) // Outputs: Gen<NSString>
printName(gen2) // Outputs: Gen<NSNumber>
再次编辑:再考虑一下,如果要向每个泛型类添加一个计算属性(您说只有3-4个属性,对吗?)然后让它看起来像这样:
class Gen<T: AnyObject> {
init() { }
var className: String {
return (reflect(self).summary.componentsSeparatedByString(".").last ?? "") + "<\(NSStringFromClass(T.self))>"
}
}
现在您可以将类名作为一个字符串获得,如下所示:
let gen1 = Gen<NSString>()
println(gen1.className) // Output: Gen<NSString>
这样,您就不会破坏协议、全局函数或NSScanner
(这可能是缓慢的.)。
https://stackoverflow.com/questions/28232474
复制