在Swift中获取对象的类名作为字符串

时间:2014-06-30 16:29:37

标签: swift

使用

获取对象的类名作为字符串
object_getClassName(myViewController)

返回类似这样的内容

_TtC5AppName22CalendarViewController

我正在寻找版本:“CalendarViewController”。如何获取类名的清理字符串?

我发现了一些有关此问题的尝试但不是真正的答案。这不可能吗?

31 个答案:

答案 0 :(得分:454)

来自实例的字符串

String(describing: YourType.self)

来自类型的字符串

String(describing: self)

示例:

struct Foo {

    // Instance Level
    var typeName: String {
        return String(describing: Foo.self)
    }

    // Instance Level - Alternative Way
    var otherTypeName: String {
        let thisType = type(of: self)
        return String(describing: thisType)
    }

    // Type Level
    static var typeName: String {
        return String(describing: self)
    }

}

Foo().typeName       // = "Foo"
Foo().otherTypeName  // = "Foo"
Foo.typeName         // = "Foo"

使用classstructenum进行了测试。

答案 1 :(得分:133)

更新为SWIFT 5

我们可以通过String初始化程序和创建某个类的新对象 使用实例变量来获取类型名称的漂亮描述

赞,例如print(String(describing: type(of: object)))。其中object可以是实例变量,例如数组,字典,IntNSDate

因为NSObject是大多数Objective-C类层次结构的根类,所以您可以尝试为NSObject创建扩展名以获取NSObject的每个子类的类名。像这样:

extension NSObject {
    var theClassName: String {
        return NSStringFromClass(type(of: self))
    }
}

或者您可以创建一个静态函数,其参数类型为Any(所有类型隐式符合的协议),并将类名返回为String。像这样:

class Utility{
    class func classNameAsString(_ obj: Any) -> String {
        //prints more readable results for dictionaries, arrays, Int, etc
        return String(describing: type(of: obj))
    }
} 

现在你可以这样做:

class ClassOne : UIViewController{ /* some code here */ }
class ClassTwo : ClassOne{ /* some code here */ }

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Get the class name as String
        let dictionary: [String: CGFloat] = [:]
        let array: [Int] = []
        let int = 9
        let numFloat: CGFloat = 3.0
        let numDouble: Double = 1.0
        let classOne = ClassOne()
        let classTwo: ClassTwo? = ClassTwo()
        let now = NSDate()
        let lbl = UILabel()

        print("diccionary: [String: CGFloat] = [:] -> \(Utility.classNameAsString(dictionary))")
        print("array: [Int] = [] -> \(Utility.classNameAsString(array))")
        print("int = 9 -> \(Utility.classNameAsString(int))")
        print("numFloat: CGFloat = 3.0 -> \(Utility.classNameAsString(numFloat))")
        print("numDouble: Double = 1.0 -> \(Utility.classNameAsString(numDouble))")
        print("classOne = ClassOne() -> \((ClassOne).self)") //we use the Extension
        if classTwo != nil {
            print("classTwo: ClassTwo? = ClassTwo() -> \(Utility.classNameAsString(classTwo!))") //now we can use a Forced-Value Expression and unwrap the value
        }
        print("now = Date() -> \(Utility.classNameAsString(now))")
        print("lbl = UILabel() -> \(String(describing: type(of: lbl)))") // we use the String initializer directly

    }
}

此外,一旦我们可以将类名称作为String,我们就可以实现该类的新对象

// Instanciate a class from a String
print("\nInstaciate a class from a String")
let aClassName = classOne.theClassName
let aClassType = NSClassFromString(aClassName) as! NSObject.Type
let instance = aClassType.init() // we create a new object
print(String(cString: class_getName(type(of: instance))))
print(instance.self is ClassOne)

也许这可以帮助那些人!

答案 2 :(得分:111)

Swift 4.2

以下是将typeName作为变量(对于值类型或引用类型)的扩展。

protocol NameDescribable {
    var typeName: String { get }
    static var typeName: String { get }
}

extension NameDescribable {
    var typeName: String {
        return String(describing: type(of: self))
    }

    static var typeName: String {
        return String(describing: self)
    }
}

使用方法:

// Extend with class/struct/enum...
extension NSObject: NameDescribable {}
extension Array: NameDescribable {}

print(UITabBarController().typeName)
print(UINavigationController.typeName)
print([Int]().typeName)

答案 3 :(得分:30)

Swift 3.0

String(describing: MyViewController.self)

答案 4 :(得分:27)

我建议采用这种方式(非常Swifty ):

// Swift 3
func typeName(_ some: Any) -> String {
    return (some is Any.Type) ? "\(some)" : "\(type(of: some))"
}

// Swift 2
func typeName(some: Any) -> String {
    return (some is Any.Type) ? "\(some)" : "\(some.dynamicType)"
}

它既不使用内省也不使用手动demangling( no magic!)。

这是一个演示:

// Swift 3

import class Foundation.NSObject

func typeName(_ some: Any) -> String {
    return (some is Any.Type) ? "\(some)" : "\(type(of: some))"
}

class GenericClass<T> {
    var x: T? = nil
}

protocol Proto1 {
    func f(x: Int) -> Int
}


@objc(ObjCClass1)
class Class1: NSObject, Proto1 {
    func f(x: Int) -> Int {
        return x
    }
}

struct Struct1 {
    var x: Int
}

enum Enum1 {
    case X
}

print(typeName(GenericClass<Int>.self)) // GenericClass<Int>
print(typeName(GenericClass<Int>()))  // GenericClass<Int>

print(typeName(Proto1.self)) // Proto1

print(typeName(Class1.self))   // Class1
print(typeName(Class1())) // Class1
print(typeName(Class1().f)) // (Int) -> Int

print(typeName(Struct1.self)) // Struct1
print(typeName(Struct1(x: 1))) // Struct1
print(typeName(Enum1.self)) // Enum1
print(typeName(Enum1.X)) // Enum1

答案 5 :(得分:18)

Swift 5.2:

String(describing: type(of: self))

答案 6 :(得分:17)

Swift 4.1 ,现在 Swift 4.2

import Foundation

class SomeClass {
    class InnerClass {
        let foo: Int

        init(foo: Int) {
            self.foo = foo
        }
    }

    let foo: Int

    init(foo: Int) {
        self.foo = foo
    }
}

class AnotherClass : NSObject {
    let foo: Int

    init(foo: Int) {
        self.foo = foo
        super.init()
    }
}

struct SomeStruct {
    let bar: Int

    init(bar: Int) {
        self.bar = bar
    }
}

let c = SomeClass(foo: 42)
let s = SomeStruct(bar: 1337)
let i = SomeClass.InnerClass(foo: 2018)
let a = AnotherClass(foo: 1<<8)

如果您没有实例:

String(describing: SomeClass.self) // Result: SomeClass
String(describing: SomeStruct.self) // Result: SomeStruct
String(describing: SomeClass.InnerClass.self) // Result: InnerClass
String(describing: AnotherClass.self) // Result: AnotherClass

如果你有一个实例:

String(describing: type(of: c)) // Result: SomeClass
String(describing: type(of: s)) // Result: SomeStruct
String(describing: type(of: i)) // Result: InnerClass
String(describing: type(of: a)) // Result: AnotherClass

答案 7 :(得分:12)

您可以像这样使用名为_stdlib_getDemangledTypeName的Swift标准库函数:

let name = _stdlib_getDemangledTypeName(myViewController)

答案 8 :(得分:11)

要在 Swift 4 中将类型名称作为字符串获取(我没有检查过早期版本),只需使用字符串插值:

"\(type(of: myViewController))"

您可以在类型本身上使用.self,在实例上使用type(of:_)函数:

// Both constants will have "UIViewController" as their value
let stringFromType = "\(UIViewController.self)"
let stringFromInstance = "\(type(of: UIViewController()))"

答案 9 :(得分:8)

您可以尝试这种方式:

a = [0, 9, 2, 2, 3, 2, 7, 5, 9, 5]
p a.chunk_while {|i, j| i <= j }.to_a

答案 10 :(得分:7)

也可以使用镜子:

let vc = UIViewController()

String(Mirror(reflecting: vc).subjectType)

注意:此方法也可用于Structs和Enums。有一个displayStyle可以指示结构的类型:

Mirror(reflecting: vc).displayStyle

返回是枚举,因此您可以:

Mirror(reflecting: vc).displayStyle == .Class

答案 11 :(得分:6)

Swift 3.0: 你可以像这样创建一个扩展名。它返回没有项目名称的类名

extension NSObject {
    var className: String {
        return NSStringFromClass(self as! AnyClass).components(separatedBy: ".").last ?? ""
    }

    public class var className: String {
        return NSStringFromClass(self).components(separatedBy: ".").last ?? ""
    }
}

答案 12 :(得分:4)

我一直在寻找这个答案。我使用GKStateMachine并喜欢观察状态变化,并想要一种简单的方法来查看类名。我不确定它只是iOS 10还是Swift 2.3,但在那种环境中,以下内容完全符合我的要求:

let state:GKState?
print("Class Name: \(String(state.classForCoder)")

// Output:    
// Class Name: GKState

答案 13 :(得分:2)

在Class self或instance dynamicType上尝试echo off REM This script is designed to demonstrate capture of volatile data from a Post Windows XP client set /p path="Enter Drive Letter " date /T > %path%:file.txt time /T >> %path%:file.txt getmac >> %path%:file.txt hostname >> %path%:file.txt ipconfig /all >> %path%:file.txt arp -a >> %path%:file.txt ipconfig /displaydns >> %path%:file.txt netstat -an >> %path%:file.txt 。获取dynamicType之前解包可选项,否则dynamicType是可选包装器。

reflect().summary

摘要是一个描述泛型类型的类路径。要从摘要中获取简单的类名,请尝试使用此方法。

class SampleClass { class InnerClass{} }
let sampleClassName = reflect(SampleClass.self).summary;
let instance = SampleClass();
let instanceClassName = reflect(instance.dynamicType).summary;
let innerInstance = SampleClass.InnerClass();
let InnerInstanceClassName = reflect(innerInstance.dynamicType).summary.pathExtension;
let tupleArray = [(Int,[String:Int])]();
let tupleArrayTypeName = reflect(tupleArray.dynamicType).summary;

答案 14 :(得分:2)

你可以像这样在Swift 4中扩展NSObjectProtocol

import Foundation

extension NSObjectProtocol {

    var className: String {
        return String(describing: Self.self)
    }
}

这将使所有类都可以使用计算变量className。在print() CalendarViewController内使用此功能将在控制台中打印"CalendarViewController"

答案 15 :(得分:2)

以上解决方案对我不起作用。主要产生的问题在几条评论中提到:

  

MyAppName.ClassName

  

MyFrameWorkName.ClassName

此解决方案适用于XCode 9,Swift 3.0:

我将其命名为Map<String, String[]> map = //Map with data try(BufferedWriter writer = new BufferedWriter(new FileWriter("<your_file>"))){ for(Map.Entry<String, String[]> entry : map.entrySet()){ writer.write(String.join(",", entry.getValue())); writer.newLine(); } } ,因此更容易访问,并且不会与未来的classNameCleaned更改发生冲突:

className()

}

用法:

extension NSObject {

static var classNameCleaned : String {

    let className = self.className()
    if className.contains(".") {
        let namesArray = className.components(separatedBy: ".")
        return namesArray.last ?? className
    } else {
        return self.className()
    }

}

答案 16 :(得分:1)

要从对象获取Swift类的名称,例如对于var对象:SomeClass(),使用

.bat

从类类型中获取Swift类的名称,例如SomeClass,使用:

String(describing: type(of: object))

输出:

  

“ SomeClass”

答案 17 :(得分:1)

此类用于var类的示例。不要包含捆绑软件的名称。

extension NSObject {
    class var className: String {
        return "\(self)"
    }
}

答案 18 :(得分:1)

雨燕5

 NSStringFromClass(CustomClass.self)

答案 19 :(得分:1)

我在Playground中使用Swift 3尝试了type(of:...)。这是我的结果。 这是代码格式版本。

print(String(describing: type(of: UIButton.self)))
print(String(describing: type(of: UIButton())))
UIButton.Type
UIButton

答案 20 :(得分:1)

Swift 3.0(macOS 10.10及更高版本),您可以从className

获取它
self.className.components(separatedBy: ".").last!

答案 21 :(得分:1)

要将类名称作为String,请将您的类声明为以下

@objc(YourClassName) class YourClassName{}

使用以下语法

获取类名
NSStringFromClass(YourClassName)

答案 22 :(得分:0)

迅速5:

方法1: print(“ Class:(String(describing:self)),Function:(#function),line:(#line)”) 输出:类:,功能:viewDidLoad(),行:15

方式2: print(“ Class:(String(describing:type(of:self))),Function:(#function),line:(#line)”) 输出:类:ViewController,功能:viewDidLoad(),行:16

答案 23 :(得分:0)

如果你不喜欢被破坏的名字,你可以指定自己的名字:

@objc(CalendarViewController) class CalendarViewController : UIViewController {
    // ...
}

但是,从长远来看,学会解析受损的名称会更好。格式标准且有意义,不会发生变化。

答案 24 :(得分:0)

Swift 5.1

您可以通过Self.self获取类,结构,枚举名称,并且可以在协议中使用它。

print("\(Self.self)")

答案 25 :(得分:0)

此解决方案适用于所有课程

Swift 5 解决方案:

extension NSObject {
  var className: String {
    return String(describing: type(of: self))
  }

  class var className: String {
    return String(describing: self)
  }
}

用法:

class TextFieldCell: UITableVIewCell {
}

class LoginViewController: UIViewController {
  let cellClassName = TextFieldCell.className
}

答案 26 :(得分:0)

Swift 5.1:-

还可以使用泛型函数将对象的类名称作为字符串获取

struct GenericFunctions {
 static func className<T>(_ name: T) -> String {
        return "\(name)"
    }

}

使用以下命令调用此函数:-

let name = GenericFunctions.className(ViewController.self)

快乐编码:)

答案 27 :(得分:0)

您可以通过以下方式获取类的名称:

class Person {}
String(describing: Person.self)

答案 28 :(得分:0)

有时其他解决方案会根据您尝试查看的对象提供无用的名称。在这种情况下,您可以使用以下内容将类名称作为字符串。

String(cString: object_getClassName(Any!))

⌘单击xcode中的函数以查看一些非常有用的相关方法。或点击此处https://developer.apple.com/reference/objectivec/objective_c_functions

答案 29 :(得分:0)

我在Swift 2.2中使用它

guard let currentController = UIApplication.topViewController() else { return }
currentController.classForCoder.description().componentsSeparatedByString(".").last!

答案 30 :(得分:-1)

在我的例子中,String(描述:self)返回了类似的内容:

  

&LT; My_project.ExampleViewController:0x10b2bb2b0&gt;

但我希望Android上有类似getSimpleName的内容。

所以我创建了一个小扩展:

extension UIViewController {

    func getSimpleClassName() -> String {
        let describing = String(describing: self)
        if let dotIndex = describing.index(of: "."), let commaIndex = describing.index(of: ":") {
            let afterDotIndex = describing.index(after: dotIndex)
            if(afterDotIndex < commaIndex) {
                return String(describing[afterDotIndex ..< commaIndex])
            }
        }
        return describing
    }

}

现在又回来了:

  

ExampleViewController

扩展NSObject而不是UIViewController也应该有效。上述功能也是故障安全的:)