使用以下方法将对象的类名获取为 String
:
object_getClassName(myViewController)
返回类似于这样的内容:
_TtC5AppName22CalendarViewController
我正在寻找纯净的版本:"CalendarViewController"
。那么如何获取一个清理过的类名字符串呢?
我找到了一些关于这个问题的尝试,但没有实际的答案。难道完全不可能吗?
使用以下方法将对象的类名获取为 String
:
object_getClassName(myViewController)
返回类似于这样的内容:
_TtC5AppName22CalendarViewController
我正在寻找纯净的版本:"CalendarViewController"
。那么如何获取一个清理过的类名字符串呢?
我找到了一些关于这个问题的尝试,但没有实际的答案。难道完全不可能吗?
实例中的字符串:
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"
使用class
、struct
和enum
进行测试。
String(describing: MyViewController.self)
,就像下面几个回答中指出的那样。 - AmitaiBFoo
重命名为Foo2
,但在别处创建了一个类Foo
,那么代码可能会出错)。在子类化的情况下,你需要使用type(of:)
或者Type.self
,具体取决于你的需求。可能更适合获取类名的是type(of:)
。 - Marián Černý更新至Swift 5
我们可以通过使用实例变量和String
初始化器,获得类型名称的漂亮描述,并创建某个类的新对象
例如: print(String(describing: type(of: object)))
。 这里的object
可以是一个数组、一个字典、一个Int
、一个NSDate
等实例变量。
因为NSObject
是大多数Objective-C类层次结构的根类,你可以尝试为NSObject
创建一个扩展,以获取每个NSObject
子类的类名。像这样:
extension NSObject {
var theClassName: String {
return NSStringFromClass(type(of: self))
}
}
或者您可以创建一个静态函数,其参数的类型为Any
(所有类型隐式符合的协议),并返回类名作为字符串。像这样:
或者你可以创建一个静态函数,它的参数类型是Any
(所有类型都隐式地符合的协议),并返回类名作为字符串。就像这样:
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
}
}
此外,一旦我们能够将类名作为字符串获取,我们就可以实例化该类的新对象:
// 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)
也许这能帮助到某个人!
classNameAsString
可以简化为 className
,因为 "name" 表示其类型。theClassName
类似于 Facebook 的故事,最初被命名为 thefacebook。 - DawnSongProjectTest.MyViewController
。我该如何去掉这个项目名称?我只想要类名。 - Sazzad Hissain Khan这里是一个扩展,可将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
Swift 5.2:
String(describing: type(of: self))
// 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
type(of: self)
获取字符串。 - Asad AliSwift 3.0
String(describing: MyViewController.self)
type(of:)
是过度设计了,String(describing: MyViewController.self)
就足够了。 - Alexander VaseninString.init(describing: MyViewController.self)
吗? - Iulian Onofreiinit
是不必要的。 - shimtype(of:)
并非过度,而是更可取的。因为如果您不使用它,则会调用debugDescription
属性。现在,如果您想要覆盖debugDescription
并在其中显示类名,那么将导致堆栈溢出。 - MooseFoo
,以下代码将在 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"
如果您只想要"Foo"
,则type(of:)
部分是不必要的。
在 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
Swift 5.1
通过Self.self
,您可以获取类、结构体、枚举、协议和NSObject的名称。
print("\(Self.self)")
String(describing: type(of: self))
不同) - User要从对象获取Swift类的名称,例如对于var object: SomeClass(),使用
String(describing: type(of: object))
获取Swift类的名称,例如SomeClass,使用以下代码:
String(describing: SomeClass.self)
输出:
"SomeClass"