在Swift中将对象的类名作为字符串获取

432

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

object_getClassName(myViewController)

返回类似于这样的内容:

_TtC5AppName22CalendarViewController

我正在寻找纯净的版本:"CalendarViewController"。那么如何获取一个清理过的类名字符串呢?

我找到了一些关于这个问题的尝试,但没有实际的答案。难道完全不可能吗?


或者说,一个有效的解析器函数应该是什么样子的? - Bernd
如果您想检查一个对象是否属于某个类,请参见此答案 - meaning-matters
32个回答

4
尝试在类自身或实例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;
}

4
上述解决方案对我没用。它们主要产生了几个评论中提到的问题:
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

4
这是一个关于类变量的例子。不包括软件包名称。
extension NSObject {
    class var className: String {
        return "\(self)"
    }
}

4

Swift 5

 NSStringFromClass(CustomClass.self)

3

这个解决方案适用于所有类

Swift 5解决方案:

extension NSObject {
  var className: String {
    return String(describing: type(of: self))
  }

  class var className: String {
    return String(describing: self)
  }
}

用法:

class TextFieldCell: UITableVIewCell {
}

class LoginViewController: UIViewController {
  let cellClassName = TextFieldCell.className
}

3

在 macOS 10.10 及更高版本中,可以从 className 获取 Swift 3.0 版本。

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

1
据我所知,在Swift类中没有内置的className属性。你是从某个类继承而来的吗? - shim
@shim className 在 Foundation 中被声明,但似乎只能在 macOS 10.10 及更高版本中使用。我刚刚编辑了我的答案。 - Thanh Vũ Trần
1
嗯,这很奇怪。为什么他们不在iOS中包含它呢?还要注意它是NSObject上的实例方法 https://developer.apple.com/reference/objectivec/nsobject/1411337-classname - shim

3
我在使用Swift 3的Playground中尝试了type(of:...),以下是我的结果。 这是代码格式版本。
print(String(describing: type(of: UIButton.self)))
print(String(describing: type(of: UIButton())))
UIButton.Type
UIButton

实例化一个实例仅仅为了确定类名是一种浪费。 - sethfri
@sethfri 我使用这个来确定动态类型。 - Lumialxk
我仍然不明白为什么需要创建一个实例来获取类的类型信息。 - sethfri

2

Swift 5.1 :-

您也可以使用通用函数将对象的类名作为字符串获取。

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

}

使用以下方式调用此函数:

let name = GenericFunctions.className(ViewController.self)

愉快的编码 :)


1
如果您不喜欢混淆的名称,您可以自己指定名称:
@objc(CalendarViewController) class CalendarViewController : UIViewController {
    // ...
}

然而,从长远来看,学习解析混淆名称会更好。其格式是标准的和有意义的,并且不会改变。


不是的,对于我的类它返回 (ExistentialMetatype) - 依赖于未记录的运行时行为总是很危险的,特别是对于 Swift 这样仍处于相对早期阶段的语言。 - superarts.org

1
有时,其他解决方案会根据您正在查看的对象而给出一个无用的名称。在这种情况下,您可以使用以下方法将类名作为字符串获取。
String(cString: object_getClassName(Any!))

在Xcode中⌘点击函数可以查看一些相关的方法,这些方法非常有用。或者在此处检查https://developer.apple.com/reference/objectivec/objective_c_functions


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接