Ответ 1
func typename (thing:Any) -> String{
let name = _stdlib_getTypeName(thing)
let demangleName = _stdlib_demangleName(name)
return demangleName.componentsSeparatedByString(".").last!
}
Я знаю утилиту командной строки swift-demangle. Я ищу что-то, что позволит мне сделать это из самого Swift.
Я был взволнован, когда увидел это после запуска :target modules dump symtab
из Swift REPL, но я не знаю, как вызвать swift_demangleSimpleClass
.
Кажется, существует команда @asmname
, которая позволяет вызывать частные функции Swift, но я не смог заставить это работать.
Вероятно, я просто напишу парсер на основе regex для этого, но вызов чего-то в самой структуре Swift кажется более безопасным.
func typename (thing:Any) -> String{
let name = _stdlib_getTypeName(thing)
let demangleName = _stdlib_demangleName(name)
return demangleName.componentsSeparatedByString(".").last!
}
В настоящий момент (XCode 6 плюс 7 бета) для классов на самом высоком уровне вы просто получаете свое приложение плюс точку плюс свое имя класса. Так что это будет что-то вроде MyApp.MyClass. Но как только вы используете подкласс, описание создается в следующих трех разделах:
Здесь особый случай. В описании также будет информация о сигнатуре функции.
Например, у вас может быть _TtCFCC5MyApp7MyClass10MySubClass6myFuncFS0_FT_T_L_11MySubSubClass
Это будет описание MySubSubClass в следующем коде:
class MyClass {
class MySubClass {
func myFunc() {
class MySubSubClass {
}
}
}
}
Здесь вы можете найти образец кода, который проанализирует это описание в простых в использовании свойствах и массивах.
Обновление: теперь Demangle преобразуется в быстрый. Вы можете найти его здесь: https://github.com/mattgallagher/CwlDemangle/blob/master/CwlDemangle/CwlDemangle.swift
Обновление: по состоянию на XCode6 beta 5, NSStringFromClass, похоже, автоматически возвращает имена с именами классов, поэтому этот код больше не нужен.
Должен быть встроенный способ сделать это, но до тех пор, пока это не произойдет, это расширение должно сделать трюк:
import Foundation
public func demangleClassName(mangled: String) -> String {
let scanner = NSScanner(string: mangled)
if (!scanner.scanString("_TtC", intoString: nil)) {
// not a mangled swift class name: Core Foundation, etc. have no module prefix
return mangled
}
var demangled = ""
var len : Int = 0
while (!scanner.atEnd && scanner.scanInteger(&len)) {
let range = Range(start:advance(mangled.startIndex, scanner.scanLocation), end: advance(mangled.startIndex, scanner.scanLocation + len))
let part = mangled.substringWithRange(range)
if (countElements(demangled) > 0) {
demangled += "."
}
demangled += part
scanner.scanLocation += len // skip to the next segment that may be prefixed by the number
}
return demangled
}
public extension NSObject {
/// demangle the current Swift object class name, as per mangling description at: http://www.eswick.com/2014/06/inside-swift/
public class func demangledClassName() -> String {
return demangleClassName(className())
}
}