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"
已通过
class
,struct
和enum
进行了测试。评论
真的是这样吗?根据此初始化程序的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
可以是实例变量,例如数组,字典,Int
,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)
也许这对那里的人有帮助!。
评论
这应该是公认的答案。谢谢,我一直在寻找一种无需实例化即可打印类名的方法,并在此处找到了答案。谢谢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.0String(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 :
方式2:
print(“ Class:(String(describing:type(of:self)))),功能: (#function),行:(#line)“)
输出:类:ViewController,函数:viewDidLoad(),行:16
评论
或者……有效的解析器功能是什么样的?如果您希望检查某个对象是否属于某个类,请参见此答案。