Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Swift中以字符串形式获取对象的类名_Swift_Reflection_Typeof - Fatal编程技术网

在Swift中以字符串形式获取对象的类名

在Swift中以字符串形式获取对象的类名,swift,reflection,typeof,Swift,Reflection,Typeof,使用以下方法将对象的类名获取为String: object_getClassName(myViewController) 返回如下内容: _TtC5AppName22CalendarViewController let name = _stdlib_getDemangledTypeName(myViewController) class ClassOne : UIViewController{ /* some code here */ } class ClassTwo : ClassOne

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

object_getClassName(myViewController)
返回如下内容:

_TtC5AppName22CalendarViewController
let name = _stdlib_getDemangledTypeName(myViewController)
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

    }
}
我正在寻找纯版本:
“CalendarViewController”
。我如何得到一个清理过的类名字符串呢


我找到了一些关于这方面的问题,但没有找到真正的答案。根本不可能吗?

如果你不喜欢这个被弄坏的名字,你可以口述自己的名字:

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

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

要将类名作为字符串,请按以下方式声明您的类

@objc(YourClassName) class YourClassName{}
并使用以下语法获取类名

NSStringFromClass(YourClassName)

您可以使用名为
\u stdlib\u getDemangledTypeName
的Swift标准库函数,如下所示:

_TtC5AppName22CalendarViewController
let name = _stdlib_getDemangledTypeName(myViewController)
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

    }
}

更新为SWIFT 5

我们可以通过
字符串
初始值设定项使用实例变量获得类型名称的漂亮描述,并创建特定类的新对象

比如
print(字符串(描述:类型(of:object)))
。其中
对象
可以是实例变量如数组、字典、
Int
NSDate

由于
NSObject
是大多数Objective-C类层次结构的根类,因此可以尝试对
NSObject
进行扩展,以获取
NSObject
的每个子类的类名。像这样:

extension NSObject {
    var theClassName: String {
        return NSStringFromClass(type(of: self))
    }
}
class Utility{
    class func classNameAsString(_ obj: Any) -> String {
        //prints more readable results for dictionaries, arrays, Int, etc
        return String(describing: type(of: obj))
    }
} 
或者,您可以创建一个静态函数,其参数类型为
Any
(所有类型都隐式符合的协议),并将类名作为字符串返回。像这样:

extension NSObject {
    var theClassName: String {
        return NSStringFromClass(type(of: self))
    }
}
class Utility{
    class func classNameAsString(_ obj: Any) -> String {
        //prints more readable results for dictionaries, arrays, Int, etc
        return String(describing: type(of: obj))
    }
} 
现在您可以执行以下操作:

_TtC5AppName22CalendarViewController
let name = _stdlib_getDemangledTypeName(myViewController)
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)
也许这对外面的人有帮助

在类自身或实例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;
}
func simpleClassName(complexClassName:String)->String{
var result=complexClassName;

var range=result.rangeOfString(我建议采用这种方法(非常迅速):

它既不使用内省也不使用手动命令(没有魔法!)


下面是一个演示:

// 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
导入类基础
func typeName(usome:Any)->字符串{
return(some是Any.Type)?“\(some)”:“\(Type(of:some))”
}
类泛型类{
变量x:T?=nil
}
协议协议1{
func f(x:Int)->Int
}
@objc(ObjCClass1)
类别1:NSObject,Proto1{
func f(x:Int)->Int{
返回x
}
}
结构1{
变量x:Int
}
枚举枚举1{
案例十
}
打印(typeName(GenericClass.self))//GenericClass
打印(typeName(GenericClass())//GenericClass
打印(typeName(Proto1.self))//Proto1
打印(typeName(Class1.self))//Class1
打印(typeName(Class1())//Class1
打印(typeName(Class1().f))/(Int)->Int
打印(typeName(Struct1.self))//Struct1
打印(typeName(Struct1(x:1))//Struct1
打印(typeName(Enum1.self))//Enum1
打印(typeName(Enum1.X))//Enum1
您可以这样尝试:

self.classForCoder.description()
实例中的字符串:

// Both constants will have "UIViewController" as their value
let stringFromType = "\(UIViewController.self)"
let stringFromInstance = "\(type(of: UIViewController()))"
类型中的字符串:

例如:

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
测试时,也可以使用镜像:

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!
Swift 3.0

字符串(描述:MyViewController.self)

Swift 5 以下是将
typeName
作为变量获取的扩展(同时使用值类型或引用类型)

如何使用:

// 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
//使用class/struct/enum进行扩展。。。
扩展NSObject:NameDescriptable{}
扩展数组:NameDescriptable{}
扩展UIBarStyle:NameDescriptable{}
打印(UITabBarController().typeName)
打印(UINavigationController.typeName)
打印([Int]().typeName)
打印(UIBarStyle.typeName)
//输出:
超宽带控制器
导航控制器
排列
UIBarStyle

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

有时,其他解决方案会根据您试图查看的对象给出一个无用的名称

String(cString: object_getClassName(Any!))
⌘ 单击xcode中的函数以查看一些非常有用的相关方法。或者在此处检查我使用Swift 3在操场中尝试了
类型(of:…)
。这是我的结果。 这是代码格式版本

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.Type”
作为结果字符串提供给您,而您真正想要的只是
“Foo”

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

如果您只想
“Foo”
Swift 4中以字符串形式获取类型名称,则不需要
类型(of:)
部分,只需使用字符串插值:

"\(type(of: myViewController))"
您可以使用
.selfString(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
String(describing: type(of: object))
String(describing: SomeClass.self)
class Person {}
String(describing: Person.self)
 NSStringFromClass(CustomClass.self)
extension NSObject {
    class var className: String {
        return "\(self)"
    }
}
struct GenericFunctions {
 static func className<T>(_ name: T) -> String {
        return "\(name)"
    }

}
let name = GenericFunctions.className(ViewController.self)
String(describing: type(of: self))