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

object_getClassName(myViewController)


返回如下内容:

_TtC5AppName22CalendarViewController


I我正在寻找纯版本:"CalendarViewController"。我该如何获取类名称的清理字符串?

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

评论

或者……有效的解析器功能是什么样的?

如果您希望检查某个对象是否属于某个类,请参见此答案。

#1 楼

来自实例的字符串:
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进行了测试。

评论


真的是这样吗?根据此初始化程序的String文档,当它不符合Streamable,CustomStringConvertible或CustomDebugStringConvertible时,“ Swift标准库会自动提供未指定的结果”。因此,尽管现在可能显示所需的值,但将来会继续显示吗?

– Tod Cunningham
16年4月13日在22:16

在Xcode 7.3.1和Swift 2.2中使用它会产生以下结果,这是不理想的。 ''让名称=字符串(自己)名称字符串“ ”''

– CodeBender
16 Jul 19 '16:39



在Swift 3中,正确的答案是调用String(描述:MyViewController.self),如以下一些答案所述。

– AmitaiB
16-10-9在20:07

但是它返回“ MyViewController.TYPE”!

–orkenstein
16 Dec 23'at 2:03

@RudolfAdamkovič是的,那是真的。但是我不喜欢显式地编写类名(如果我将类Foo重命名为Foo2却在其他地方创建了类Foo,那可能会破坏代码)。如果是子类,则需要根据需要使用type(of :)或Type.self。 type(of :)可能更适合于获取类名。

–MariánČerný
18 Mar 15 '18在16:22

#2 楼

更新到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)


也许这对那里的人有帮助!。

评论


这应该是公认的答案。谢谢,我一直在寻找一种无需实例化即可打印类名的方法,并在此处找到了答案。谢谢print(String(BaseAsyncTask))

–布鲁诺·科埃略(Bruno Coelho)
15-10-27在14:16



可以将classNameAsString简化为className,因为该“名称”表示其类型。 theClassName与facebook的故事类似,最初被称为thefacebook。

–黎明之歌
16-10-19在5:26

“字典” ... Swift字典集的意大利语版本:]

–安德鲁·基尔纳(Andrew Kirna)
19年6月26日在21:35

该解决方案在每个classTag的项目名称之前,即ProjectTest.MyViewController。我如何摆脱这个项目名称?我只想要班级名称。

– Sazzad Hissain Khan
19年11月1日在7:50

#3 楼

Swift 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


评论


任何想法为什么我得到MyAppName.MyClassName呢?我只对MyClassName感兴趣

–安德鲁(Andrew)
16-11-27在21:00

@Andrew您能否针对您的情况提供更具体的信息?我在许多项目中都使用了此扩展名,并且所有项目都按预期进行了响应。

– nahung89
16年11月28日在8:09

好吧,如果我从类本身调用它,则返回MyClassName,但如果将其包装在返回类名称字符串的方法中,并从另一个类调用它,则返回MyAppName.MyClassName。在搜索时,我发现所有类都隐式命名空间,因此,如果要在类外部调用它,则会得到MyAppName.MyClassName而不是MyClassName。然后,您必须依靠字符串操作来获取类名称。

–安德鲁(Andrew)
16-11-28在13:59

非常有用的扩展

–哈托里(HattoriHanzō)
18年11月8日在7:24

@Andrew,不确定当前的工作方式,但我记得String(描述:type(of:self))曾经在某一时刻返回ModuleName.ClassName。我基于进行了拆分。字符并获取了最后一个对象。

– BangOperator
19年6月21日在5:42



#4 楼

雨燕3.0

String(describing: MyViewController.self)

评论


实际上,type(of:)在这里是一个过大的杀伤力,String(描述:MyViewController.self)就足够了

–亚历山大·瓦森宁(Alexander Vasenin)
16-09-24在8:26

这会为我创建一个字符串,例如

–道格·阿莫斯(Doug Amos)
16-10-3在10:23

是不是String.init(描述为:MyViewController.self)?

–尤利安·奥诺夫雷(Iulian Onofrei)
16年11月5日在23:27

@IulianOnofrei,您可以执行此操作,但不需要初始化。

–垫片
16-12-12在17:46



完全摆脱了AppName前缀!谢谢

– yuchen
17年8月10日在6:53

#5 楼

我建议采用这种方法(非常快速):

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


评论


他们在Swift 3.0中对其进行了更改。现在您可以从type(of:self)获取字符串

–阿萨德·阿里(Asad Ali)
17 Mar 10 '17 at 12:43

更新至Swift 3。

–潜水员
17年3月11日在9:19

我认为这是获取类型名称的最佳方法:基于NSObject,枚举,类型别名,函数,var属性以及任何类型(甚至常量)的任何类实例。对于类型,必须使用.self。例如,typeName(Int.self),typeName(true.self)。您也不必担心项目名称作为一部分(例如AppProj。[typename])。

– David.Chu.ca
18-10-16在17:53



#6 楼

如果您输入的是Foo类型,则以下代码将在Swift 3和Swift 4中为您提供"Foo"

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


此处大多数答案的问题是它们给如果没有任何类型的实例,而您真正想要的只是"Foo.Type",则将"Foo"作为结果字符串。如其他答案中所述,以下内容为您提供了"Foo.Type"

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


如果只需要type(of:),则不需要"Foo"部分。

#7 楼

在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


#8 楼

Swift 5.2:

String(describing: type(of: self))


#9 楼

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

String(describing: type(of: object))


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

String(describing: SomeClass.self)


输出:


“ SomeClass”


#10 楼

Swift 5.1

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

 print("\(Self.self)")
 


评论


请注意,这可能在模块名称之前(不同于String(描述:type(of:self)))

– Ixx
20年4月4日在14:51

#11 楼

您可以这样尝试:

self.classForCoder.description()


评论


由于它包括完整的“命名空间”(适当的目标成员资格前缀),因此效果很好。

– BonanzaDriver
16-2-4在21:54

顺便说一句,我还发现使用“ String(self)”,其中self也是MyViewController的一个实例,它也提供相同的信息……Xcode 7.1。

– BonanzaDriver
16-2-5在14:42



#12 楼

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

let name = _stdlib_getDemangledTypeName(myViewController)


评论


@NeilJaff“仅是可选字符串”是什么意思?它返回一个字符串,并且不是可选的。

–Jernej Strasner
15年3月20日在14:50

这种方法不会返回专用API FYI中的类的名称。它将返回第一个公共基类名称的名称。

– Tylerc230
2015年9月15日19:11

我收到消息:使用未解析的标识符'_stdlib_getDemangledTypeName'

– Blazej SLEBODA
19-09-5在18:03

#13 楼

要在Swift 4中将类型名称作为字符串获取(我尚未检查较早的版本),只需使用字符串插值即可:

"\(type(of: myViewController))"


您可以在类型本身,以及实例上的.self函数:

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


#14 楼

也可以使用镜子:

let vc = UIViewController()

String(Mirror(reflecting: vc).subjectType)


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

Mirror(reflecting: vc).displayStyle


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

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


评论


谢谢。那对我有用。唯一的事情(至少在iOS 9上是如此)是subjectType以“ .Type”结尾,因此我不得不从字符串中删除该部分。

– Nikolay Suvandzhiev
16年6月6日在8:11

#15 楼

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 ?? ""
    }
}


评论


当我尝试使用此方法时,出现错误:无法将类型'ProjectName.MyViewController'(0x1020409e8)的值强制转换为'Swift.AnyObject.Type'(0x7fb96fc0dec0)。

–tylerSF
17年2月2日在21:06

#16 楼

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

import Foundation

extension NSObjectProtocol {

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


这将使计算出的变量className可用于所有类。在print()中的CalendarViewController内部使用它会在控制台中打印"CalendarViewController"

#17 楼

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

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

// Output:    
// Class Name: GKState


#18 楼

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

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


#19 楼

要以String形式获取类名称,请按照以下说明声明您的类

@objc(YourClassName) class YourClassName{}


,并使用以下语法获取类名称

NSStringFromClass(YourClassName)


#20 楼

在Class self或instance dynamicType上尝试reflect().summary。在获取dynamicType之前,请先取消包装可选项,否则,否则dynamicType是Optional包装器。

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;
}


#21 楼

上述解决方案对我不起作用。产生的问题大多在以下注释中提及:


MyAppName.ClassName





MyFrameWorkName.ClassName


此解决方案适用于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


#22 楼

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

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


评论


据我所知,Swift类中没有内置的className属性。你是从某种事物中继承出来的吗?

–垫片
16-12-12在17:45



@shim className在Foundation中声明,但似乎仅在macOS 10.10及更高版本上可用。我刚刚编辑了答案。

–感谢VũTrần
16 Dec 13'在10:14

嗯,这很奇怪。他们为什么不将其包含在iOS中?还要注意,这是NSObject developer.apple.com/reference/objectivec/nsobject / ...上的实例方法。

–垫片
16-12-13在15:53



#23 楼

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

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


评论


实例化实例只是为了确定类名是浪费的。

–sethfri
17年5月8日在7:43



@sethfri我用它来确定动态类型。

– Lumialxk
17年5月11日在14:47

我仍然不明白为什么您只需要创建一个实例来获取类的类型信息

–sethfri
17年5月15日在23:41

#24 楼

雨燕5

 NSStringFromClass(CustomClass.self)


#25 楼

类var的这种示例。不要包含捆绑软件的名称。

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


#26 楼

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

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


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

评论


不,不是,对于我的类,它返回(ExistentialMetatype)-依赖未记录的运行时行为总是很危险的,尤其是对于swift来说,因为它仍处于相对早期。

–superarts.org
2014年9月23日下午3:33

#27 楼

有时,其他解决方案会根据您要查看的对象而给出无效的名称。在这种情况下,您可以使用以下命令将类名作为字符串获取。

String(cString: object_getClassName(Any!))


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

#28 楼

Swift 5.1:-

还可以使用泛型函数以字符串形式获取对象的类名

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

}


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

let name = GenericFunctions.className(ViewController.self)


快乐编码:)

#29 楼

我在Swift 2.2中使用它

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


#30 楼

Swift 5:
方法1:
print(“ Class:((String(describing:self)),Function:(#function),line:(#line)”)
输出:Class :,功能:viewDidLoad(),第15行:
方式2:
print(“ Class:(String(describing:type(of:self)))),功能: (#function),行:(#line)“)
输出:类:ViewController,函数:viewDidLoad(),行:16