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

使用以下方法获取对象的类名String:

object_getClassName(myViewController)

返回如下内容:

_TtC5AppName22CalendarViewController

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

我发现了一些关于这个问题的尝试,但没有一个实际的答案。难道根本不可能吗?

289009 次浏览

如果你不喜欢这个乱七八糟的名字,你可以口述你自己的名字:

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

然而,从长远来看,最好是学会解析这个混乱的名称。格式是标准的、有意义的,不会改变。

要获得类名为String,请按以下方式声明类

@objc(YourClassName) class YourClassName{}

并使用以下语法获取类名

NSStringFromClass(YourClassName)

你可以像这样使用Swift标准库函数_stdlib_getDemangledTypeName:

let name = _stdlib_getDemangledTypeName(myViewController)

更新到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("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


}
}

此外,一旦我们可以获得类名String, 我们可以实例化该类的新对象:

// Instantiate a class from a String
print("\nInstantiate 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)

也许这能帮助一些人!

在类self或实例dynamicType上尝试reflect().summary。在获取dynamicType之前解开可选项,否则dynamicType是可选包装器。

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;

摘要是描述了泛型类型的类路径。要从摘要中获得简单的类名,请尝试此方法。

func simpleClassName( complexClassName:String ) -> String {
var result = complexClassName;
var range = result.rangeOfString( "<" );
if ( nil != range ) { result = result.substringToIndex( range!.startIndex ); }
range = result.rangeOfString( "." );
if ( nil != range ) { result = result.pathExtension; }
return result;
}

我建议这样的方法(非常中高阶层):

// 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)"
}

它既不使用自省也不使用手动提取(没有魔法!)。


下面是一个演示:

// 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

你可以试试这种方法:

self.classForCoder.description()

实例中的字符串:

String(describing: self)

类型中的字符串:

String(describing: YourType.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测试。

你也可以使用镜子:

let vc = UIViewController()


String(Mirror(reflecting: vc).subjectType)

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

Mirror(reflecting: vc).displayStyle

返回值是一个枚举,所以你可以:

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

我在Swift 2.2中使用它

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

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

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


// Output:
// Class Name: GKState

Swift 3.0 (macOS 10.10及更高版本),你可以从className中获取它

self.className.components(separatedBy: ".").last!

斯威夫特3.0

String(describing: MyViewController.self)

斯威夫特5

下面是获取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 {}
extension UIBarStyle: NameDescribable { }


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


// Out put:
UITabBarController
UINavigationController
Array<Int>
UIBarStyle

< >强劲迅速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 ?? ""
}
}

有时其他解决方案会给出一个无用的名称,这取决于您试图查看的对象。在这种情况下,您可以使用以下命令获取类名作为字符串。

String(cString: object_getClassName(Any!))

⌘单击xcode中的函数,查看一些相当有用的相关方法。或检查这里https://developer.apple.com/reference/objectivec/objective_c_functions

我尝试了type(of:...)在操场与Swift 3。这是我的结果。 . 这是代码格式版本

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

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

let className = String(describing: Foo.self) // Gives you "Foo"

这里大多数答案的问题是,当你没有任何类型的实例时,当你真正想要的只是"Foo"时,它们会给你"Foo.Type"作为结果字符串。下面给出了"Foo.Type",正如在其他一些答案中提到的那样。

let className = String(describing: type(of: Foo.self)) // Gives you "Foo.Type"

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

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

"\(type(of: myViewController))"

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

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

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

MyAppName。类名称

MyFrameWorkName。类名称

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

我将其命名为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()
}


}

用法:

NSViewController.classNameCleaned
MyCustomClass.classNameCleaned

在我的例子中,String(description: self)返回如下内容:

& lt;My_project。ExampleViewController: 0 x10b2bb2b0 >

但我想在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也可以。上面的函数也是故障安全的:)

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

import Foundation


extension NSObjectProtocol {


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

这将使计算变量className对所有类可用。在CalendarViewController中的print()中使用此函数将在控制台中打印"CalendarViewController"

斯威夫特4.1和现在的斯威夫特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

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

String(describing: type(of: object))

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

String(describing: SomeClass.self)

输出:

“SomeClass”

你可以通过如下方式获取类名:

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

斯威夫特5

 NSStringFromClass(CustomClass.self)

这类例子用于类var.不要包含bundle的名称。

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

Swift 5.1:-

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

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


}

使用以下方法调用此函数:-

let name = GenericFunctions.className(ViewController.self)

快乐编码:)

斯威夫特5.1

你可以通过Self.self获取类、结构、枚举、协议和NSObject名称。

print("\(Self.self)")

斯威夫特5.2:

String(describing: type(of: self))

斯威夫特5:

方式1:

print("Class: \(String(describing: self)), Function: \(#function), line: \(#line)")

输出:

Class: <Test.ViewController: 0x7ffaabc0a3d0>, Function: viewDidLoad(), line: 15

方式2:

print("Class: \(String(describing: type(of: self))), Function: \(#function), line: \(#line)")

输出:

Class: ViewController, Function: viewDidLoad(), line: 16

这个解决方案适用于所有的类

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
}