Answers:
实例中的字符串:
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"
经测试class
,struct
和enum
。
String(describing: MyViewController.self)
按照下面几个答案中的说明进行呼叫。
Foo
为Foo2
却在Foo
其他地方创建了一个类,那可能会破坏代码)。在子类化的情况下,您需要使用type(of:)
或Type.self
根据需要选择适合的子类。可能type(of:)
更适合于获取类名。
更新为SWIFT 5
我们可以通过初始化程序使用实例变量获得漂亮的类型名称描述,String
并创建特定类的新对象
例如print(String(describing: type(of: object)))
。在哪里object
可以是实例变量,例如数组,字典,an Int
,a NSDate
等。
因为它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)
也许这可以帮助某个人!
classNameAsString
可以简化为className
,因为该“名称”表示其类型。theClassName
与facebook的故事相似,最初被称为thefacebook。
ProjectTest.MyViewController
。我如何摆脱这个项目名称?我只想要班级名称。
这是获取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
String(describing: MyViewController.self)
type(of: )
,在那儿String(describing: MyViewController.self)
已经足够大了,就足够了
String.init(describing: MyViewController.self)
?
init
没有必要。
我建议这样一种方法(非常迅速):
// 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)
如果您具有type Foo
,则以下代码将"Foo"
在Swift 3和Swift 4中为您提供:
let className = String(describing: Foo.self) // Gives you "Foo"
此处大多数答案的问题在于,"Foo.Type"
当您没有任何类型的实例时,当您真正想要的是just时,它们将为您提供结果字符串"Foo"
。如"Foo.Type"
其他答案中所述,以下内容为您提供了。
let className = String(describing: type(of: Foo.self)) // Gives you "Foo.Type"
type(of:)
如果您只是想要,则不需要该部分"Foo"
。
在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类的名称,例如var对象:SomeClass(),请使用
String(describing: type(of: object))
要从类类型(例如SomeClass)中获取Swift类的名称,请使用:
String(describing: SomeClass.self)
输出:
“ SomeClass”
您可以这样尝试:
self.classForCoder.description()
您可以使用如下所示的Swift标准库函数_stdlib_getDemangledTypeName
:
let name = _stdlib_getDemangledTypeName(myViewController)
要在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()))"
一个人也可以使用镜子:
let vc = UIViewController()
String(Mirror(reflecting: vc).subjectType)
注意:此方法也可以用于结构体和枚举。有一个displayStyle可以指示结构的类型:
Mirror(reflecting: vc).displayStyle
返回值是一个枚举,因此您可以:
Mirror(reflecting: vc).displayStyle == .Class
迅捷5.1
您可以通过获取类,结构,枚举,协议和NSObject名称Self.self
。
print("\(Self.self)")
String(describing: type(of: self))
)
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 ?? ""
}
}
您可以NSObjectProtocol
像这样在Swift 4中进行扩展:
import Foundation
extension NSObjectProtocol {
var className: String {
return String(describing: Self.self)
}
}
这将使计算出的变量className
可用于所有类。在print()
in中使用此命令CalendarViewController
将"CalendarViewController"
在控制台中打印。
您可以通过以下方式获取类的名称:
class Person {}
String(describing: Person.self)
要获取类名称为String,请声明您的类,如下所示
@objc(YourClassName) class YourClassName{}
并使用以下语法获取类名称
NSStringFromClass(YourClassName)
尝试reflect().summary
Class自身或实例dynamicType。在获取dynamicType之前,请先取消包装Optionals,否则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;
}
上述解决方案对我不起作用。产生的问题主要在几条评论中提到:
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
Swift 3.0(macOS 10.10及更高版本),您可以从className获取它
self.className.components(separatedBy: ".").last!
NSObject
developer.apple.com/reference/objectivec/nsobject/…
类var的这种示例。不要包含捆绑包的名称。
extension NSObject {
class var className: String {
return "\(self)"
}
}
如果您不喜欢名字乱七八糟的名字,可以指定自己的名字:
@objc(CalendarViewController) class CalendarViewController : UIViewController {
// ...
}
但是,从长远来看,学习解析错误的名称会更好。格式是标准且有意义的,不会更改。
有时,其他解决方案会根据您要查看的对象而给出无效的名称。在这种情况下,您可以使用以下命令将类名作为字符串获取。
String(cString: object_getClassName(Any!))
⌘单击xcode中的函数以查看一些相当有用的相关方法。或在这里查看https://developer.apple.com/reference/objectivec/objective_c_functions
我type(of:...)
在Swift 3的Playground中尝试过。这是我的结果。
这是代码格式版本。
print(String(describing: type(of: UIButton.self)))
print(String(describing: type(of: UIButton())))
UIButton.Type
UIButton
我在Swift 2.2中使用它
guard let currentController = UIApplication.topViewController() else { return }
currentController.classForCoder.description().componentsSeparatedByString(".").last!
在我的情况下,String(describing:self)返回了以下内容:
<My_project.ExampleViewController:0x10b2bb2b0>
但我想getSimpleName
在Android上拥有类似功能。
所以我创建了一个扩展:
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也应该起作用。上面的功能也是故障安全的:)