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

Ber*_*rnd 287 swift

使用获取对象的类名作为字符串

object_getClassName(myViewController)
Run Code Online (Sandbox Code Playgroud)

返回这样的东西

_TtC5AppName22CalendarViewController
Run Code Online (Sandbox Code Playgroud)

我正在寻找版本:"CalendarViewController".如何获得清理的类名字符串?

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

Rud*_*vič 493

来自实例的字符串:

String(describing: YourType.self)
Run Code Online (Sandbox Code Playgroud)

类型中的字符串:

String(describing: self)
Run Code Online (Sandbox Code Playgroud)

例:

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"
Run Code Online (Sandbox Code Playgroud)

经过测试class,structenum.

  • 在Swift 3中,正确的答案是调用`String(描述:MyViewController.self)`,如下面的几个答案中所述. (12认同)
  • 但它返回"MyViewController.TYPE"! (8认同)
  • 这是真的吗?根据这个初始化程序的String文档,当Swift标准库不符合Streamable,CustomStringConvertible或CustomDebugStringConvertible时,"未指定的结果由Swift标准库自动提供".因此,虽然它现在可能正在显示所需的值,但它将来会继续这样做吗? (4认同)
  • 在Xcode 7.3.1和Swift 2.2中使用它会产生以下结果,这并不理想.''let name = String(self)name String"<MyAppName.MyClassName:0x ########>"'' (2认同)
  • @RudolfAdamkovič是的,那是真的.但我不喜欢明确地编写类名(如果我将类'Foo`重命名为`Foo2`但在别处创建一个类`Foo`,那可能会使代码失效).在子类化的情况下,你需要使用`type(of:)`或`Type.self`取决于你的需要.可能`type(of:)`更适合获取类名. (2认同)
  • “替代方式”应该是主要方式。 (2认同)

mau*_*nde 161

更新SWIFT 4.2

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

比如,例如print(String(describing: type(of: object))).哪里object可以是一个实例变量,如数组,字典,a Int,a NSDate等.

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

extension NSObject {
    var theClassName: String {
        return NSStringFromClass(type(of: self))
    }
}
Run Code Online (Sandbox Code Playgroud)

或者你可以创建一个静态函数,其参数是类型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))
    }
} 
Run Code Online (Sandbox Code Playgroud)

现在你可以这样做:

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("dictionary: [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

    }
}
Run Code Online (Sandbox Code Playgroud)

此外,一旦我们可以将类名称作为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)
Run Code Online (Sandbox Code Playgroud)

也许这有助于那里的人!

  • `classNameAsString`可以简化为`className`,因为"name"暗示了它的类型.`theClassName`与facebook的故事相似,最初名为thefacebook. (4认同)
  • 这应该是公认的答案.谢谢,我正在寻找一种打印类名的方法,而不必实例化它,并在这里找到答案.谢谢print(String(BaseAsyncTask)) (2认同)

nah*_*g89 117

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

如何使用:

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

print(UITabBarController().typeName)
print(UINavigationController.typeName)
print([Int]().typeName)
Run Code Online (Sandbox Code Playgroud)

  • 知道为什么我从中得到MyAppName.MyClassName吗?我只对MyClassName感兴趣 (10认同)
  • 好吧,如果我从类本身调用它,它会返回 MyClassName,但是如果我将它包装在一个返回类名字符串的方法中并从另一个类调用它,它会返回 MyAppName.MyClassName。在四处搜索时,我发现所有类都是隐式命名空间的,因此如果您要在类之外调用它,则会得到 MyAppName.MyClassName 而不是 MyClassName。然后你必须依靠字符串操作来获取类名。 (2认同)
  • 非常有用的扩展 (2认同)

sli*_*lim 31

Swift 3.0

String(describing: MyViewController.self)

  • 实际上`type(of:)`在那里是一种矫枉过正,`String(描述:MyViewController.self)`就足够了 (2认同)
  • 这为我创建了一个字符串,例如<App_Name.ClassName:0x79e14450>,这是不理想的 (2认同)
  • @IulianOnofrei,您可以执行此操作,但是不需要使用`init`。 (2认同)

wer*_*ver 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)"
}
Run Code Online (Sandbox Code Playgroud)

它既不使用内省也不使用手动解码(没有魔法!).


这是一个演示:

// 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
Run Code Online (Sandbox Code Playgroud)


Abd*_*hed 26

斯威夫特 5.2:

String(describing: type(of: self))
Run Code Online (Sandbox Code Playgroud)


set*_*fri 22

如果你有类型Foo,下面的代码将"Foo"在Swift 3和Swift 4中给你:

let className = String(describing: Foo.self) // Gives you "Foo"
Run Code Online (Sandbox Code Playgroud)

这里的大多数答案的问题是,"Foo.Type"当你没有任何类型的实例时,它们会将你作为结果字符串,当你真正想要的只是"Foo".以下为您"Foo.Type"提供了一些其他答案中提到的内容.

let className = String(describing: type(of: Foo.self)) // Gives you "Foo.Type"
Run Code Online (Sandbox Code Playgroud)

type(of:)如果你只是想要,这部分是不必要的"Foo".


Vic*_*rov 19

斯威夫特 5.1

你可以得到类、结构、枚举、协议和 NSObject 名称Self.self

print("\(Self.self)")
Run Code Online (Sandbox Code Playgroud)

  • 这不适用于发布构建配置,它将以字符串形式返回 Self。有什么好的解释为什么会发生这种情况吗? (3认同)

McN*_*ght 18

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)
Run Code Online (Sandbox Code Playgroud)

如果您没有实例:

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
Run Code Online (Sandbox Code Playgroud)

如果你有一个实例:

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
Run Code Online (Sandbox Code Playgroud)


Ash*_*iya 15

斯威夫特5:

方式一:

print("Class: \(String(describing: self)), Function: \(#function), line: \(#line)")
Run Code Online (Sandbox Code Playgroud)

输出:

Class: <Test.ViewController: 0x7ffaabc0a3d0>, Function: viewDidLoad(), line: 15
Run Code Online (Sandbox Code Playgroud)

方式二:

print("Class: \(String(describing: type(of: self))), Function: \(#function), line: \(#line)")
Run Code Online (Sandbox Code Playgroud)

输出:

Class: ViewController, Function: viewDidLoad(), line: 16
Run Code Online (Sandbox Code Playgroud)


Jer*_*ner 12

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

let name = _stdlib_getDemangledTypeName(myViewController)
Run Code Online (Sandbox Code Playgroud)

  • 此方法不返回私有API FYI中的类的名称.它将返回第一个公共基类名称的名称. (3认同)

小智 11

你可以这样试试:

self.classForCoder.description()
Run Code Online (Sandbox Code Playgroud)


Mis*_*nko 11

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

"\(type(of: myViewController))"
Run Code Online (Sandbox Code Playgroud)

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

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


小智 8

您可以NSObjectProtocol像这样在 Swift 4 中进行扩展:

import Foundation

extension NSObjectProtocol {

    var className: String {
        return String(describing: Self.self)
    }
}
Run Code Online (Sandbox Code Playgroud)

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


Pau*_*anu 7

也可以使用镜子:

let vc = UIViewController()

String(Mirror(reflecting: vc).subjectType)
Run Code Online (Sandbox Code Playgroud)

注意:此方法也可用于结构和枚举.有一个displayStyle可以指示结构的类型:

Mirror(reflecting: vc).displayStyle
Run Code Online (Sandbox Code Playgroud)

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

Mirror(reflecting: vc).displayStyle == .Class
Run Code Online (Sandbox Code Playgroud)


Exc*_*ion 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 ?? ""
    }
}
Run Code Online (Sandbox Code Playgroud)


Gur*_*ngh 6

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

String(describing: type(of: object))
Run Code Online (Sandbox Code Playgroud)

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

String(describing: SomeClass.self)
Run Code Online (Sandbox Code Playgroud)

输出:

“ SomeClass”


Moi*_*din 5

要将类名作为字符串声明您的类,如下所示

@objc(YourClassName) class YourClassName{}
Run Code Online (Sandbox Code Playgroud)

并使用以下语法获取类名

NSStringFromClass(YourClassName)
Run Code Online (Sandbox Code Playgroud)


Tro*_*roy 5

我一直在断断续续地寻找这个答案。我使用 GKStateMachine 并且喜欢观察状态变化并且想要一种简单的方法来查看类名。我不确定它是否只是 iOS 10 或 Swift 2.3,但在该环境中,以下内容正是我想要的:

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

// Output:    
// Class Name: GKState
Run Code Online (Sandbox Code Playgroud)


小智 5

您可以通过执行以下操作来获取类的名称:

class Person {}
String(describing: Person.self)
Run Code Online (Sandbox Code Playgroud)


mat*_*att 1

如果您不喜欢损坏的名称,您可以指定自己的名称:

@objc(CalendarViewController) class CalendarViewController : UIViewController {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

然而,从长远来看,学习解析损坏的名称会更好。格式是标准的、有意义的,不会改变。