Swift에서 객체의 클래스 이름을 문자열로 가져옵니다.


320

다음을 String사용하여 객체의 클래스 이름을 가져옵니다 .

object_getClassName(myViewController)

다음과 같은 것을 반환합니다 :

_TtC5AppName22CalendarViewController

순수한 버전을 찾고 "CalendarViewController"있습니다. 대신 클래스 이름의 정리 된 문자열을 어떻게 얻 습니까?

나는 이것에 관한 몇 가지 시도를 발견했지만 실제 답변은 아닙니다. 전혀 가능하지 않습니까?


대안 적으로… 이것에 대한 효과적인 파서 기능은 어떤 모습일까요?
Bernd

객체가 특정 클래스인지 확인하려면 이 답변을 참조하십시오 .
의미 문제

답변:


529

인스턴스의 문자열 :

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, structenum.


4
이것이 사실입니까? 이 이니셜 라이저의 String 문서에 따르면 Streamable, CustomStringConvertible 또는 CustomDebugStringConvertible을 준수하지 않으면 "지정되지 않은 결과가 Swift 표준 라이브러리에 의해 자동으로 제공됩니다". 이제 원하는 값을 표시 할 수 있지만 앞으로도 계속 적용됩니까?
Tod Cunningham

3
Xcode 7.3.1 & Swift 2.2에서 이것을 사용하면 다음과 같은 결과가 나옵니다. ''let name = String (self) name 문자열 "<MyAppName.MyClassName : 0x ########>" ''
CodeBender

13
Swift 3에서 올바른 답변은 String(describing: MyViewController.self)아래의 몇 가지 답변에 명시된대로 전화 하는 것입니다.
AmitaiB

10
그러나 "MyViewController.TYPE"을 반환합니다!
orkenstein

3
@ RudolfAdamkovič 네, 맞습니다. 그러나 클래스 이름을 명시 적으로 쓰는 것을 좋아하지 않습니다 (클래스 이름을 바꾸고 다른 곳 에서 클래스 FooFoo2만들면 Foo코드가 손상 될 수 있음). 서브 클래 싱의 경우 필요에 맞는 것을 사용 type(of:)하거나 Type.self의존해야합니다. type(of:)클래스 이름을 얻는 데 더 적합 할 것 입니다.
Marián Černý

182

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(모든 유형이 내재적으로 준수하는 프로토콜) 인 정적 기능을 작성 하고 클래스 이름을 문자열로 리턴 할 수 있습니다. 이처럼 :

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)

어쩌면 이것은 누군가를 도울 수 있습니다!.


2
이것은 정답입니다. 감사합니다. 클래스 이름을 인스턴스화하지 않고 인쇄하는 방법을 찾고 있었고 여기에서 답을 찾았습니다. 감사합니다 print (String (BaseAsyncTask))
Bruno Coelho

4
classNameAsStringclassName"이름"에 해당 유형이 포함 되어 있기 때문에로 단순화 될 수 있습니다 . theClassName페이스 북의 이야기와 비슷하며, 페이스 북의 이름은 원래입니다.
DawnSong

"치과"... 스위프트 사전 컬렉션의 이탈리아어 버전 :]
Andrew Kirna

이 솔루션은 각 classTag에 대해 프로젝트 이름을 앞에 추가 ProjectTest.MyViewController합니다. 이 프로젝트 이름을 제거하려면 어떻게합니까? 수업 이름 만 원합니다.
Sazzad Hissain Khan

132

스위프트 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

12
왜 내가 MyAppName.MyClassName을 가져 오는지 알 수 있습니까? 나는 MyClassName에 관심이 있습니다
Andrew

@Andrew 귀하의 경우에 좀 더 구체적으로 설명해 주시겠습니까? 많은 프로젝트에서이 확장을 사용하고 있으며 모두 의도 한대로 응답합니다.
nahung89

1
클래스 자체에서 호출하면 MyClassName을 반환하지만 클래스 이름 문자열을 반환하는 메서드로 래핑하고 다른 클래스에서 호출하면 MyAppName.MyClassName을 반환합니다. 주변을 검색하는 동안 모든 클래스가 암시 적으로 네임 스페이스라는 것을 알았으므로 클래스 외부에서 호출하면 MyClassName 대신 MyAppName.MyClassName을 얻습니다. 그런 다음 클래스 이름을 얻으려면 문자열 조작에 의존해야합니다.
Andrew

1
매우 유용한 확장
핫토리 한조

@Andrew, 현재 작동하는지 확실하지 않지만 한 시점에서 ModuleName.ClassName을 반환하는 데 사용 된 String (describing : type (of : self))을 기억합니다. 에 따라 분할했습니다. 문자와 마지막 개체를 가져 왔습니다.
BangOperator 2016 년

31

스위프트 3.0

String(describing: MyViewController.self)


2
실제로 type(of: )거기에 과잉입니다, String(describing: MyViewController.self)충분할 것입니다
Alexander Vasenin

2
이것은 나를 위해 <App_Name.ClassName : 0x79e14450>과 같은 문자열을 만듭니다. 이상적이지 않습니다
Doug Amos

그렇지 String.init(describing: MyViewController.self)않습니까?
Iulian Onofrei

2
@IulianOnofrei, 당신은 할 수 있지만 init 불필요합니다.
shim

AppName 접두사를 완전히 제거하십시오! 감사합니다
yuchen

28

나는 그런 접근 방식을 제안합니다 ( 매우 Swifty ).

// 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

스위프트 3으로 업데이트
wasdiver

NSObject, enum, typealiase, 함수, var 속성 및 모든 유형, 상수를 기반으로하는 클래스의 인스턴스 인 유형 이름을 얻는 가장 좋은 방법이라고 생각합니다. 유형의 경우 .self를 사용해야합니다. 예를 들어 typeName (Int.self), typeName (true.self)입니다. 또한 AppProj. [typename]과 같은 부분으로 프로젝트 이름을 걱정할 필요가 없습니다.
David.Chu.ca

23

type Foo을 사용하면 다음 코드 "Foo"에서 Swift 3 및 Swift 4를 제공합니다.

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".


21

에서 스위프트 4.1 지금 스위프트 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

14

객체에서 Swift 클래스의 이름을 가져 오려면 (예 : var 객체 : SomeClass ())

String(describing: type(of: object))

클래스 유형 (예 : SomeClass)에서 Swift 클래스의 이름을 가져 오려면 다음을 사용하십시오.

String(describing: SomeClass.self)

산출:

"SomeClass"


13

이 방법으로 시도 할 수 있습니다 :

self.classForCoder.description()

이것은 전체 "네임 스페이스"(적절한 대상 멤버쉽 접두사)도 포함하므로 훌륭하게 작동합니다.
BonanzaDriver

BTW, 또한 self가 MyViewController의 인스턴스 인 "String (self)"를 사용하는 것을 발견했습니다 ... 동일한 정보를 제공합니다 ... Xcode 7.1.
BonanzaDriver

12

다음 _stdlib_getDemangledTypeName과 같은 Swift 표준 라이브러리 함수를 사용할 수 있습니다 .

let name = _stdlib_getDemangledTypeName(myViewController)

@NeilJaff "선택적인 문자열"이란 무엇입니까? 문자열을 반환하며 선택 사항이 아닙니다.
Jernej Strasner

3
이 접근법은 개인 API FYI에서 클래스 이름을 반환하지 않습니다. 첫 번째 공개 기본 클래스 이름을 리턴합니다.
Tylerc230

메시지가 표시됩니다. 확인되지 않은 식별자 '_stdlib_getDemangledTypeName'사용
Adobels

12

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()))"

8

거울을 사용할 수도 있습니다.

let vc = UIViewController()

String(Mirror(reflecting: vc).subjectType)

주의 :이 방법은 Structs와 Enum에도 사용할 수 있습니다. 구조의 유형을 나타내는 displayStyle이 있습니다.

Mirror(reflecting: vc).displayStyle

반환은 열거 형이므로 다음을 수행 할 수 있습니다.

Mirror(reflecting: vc).displayStyle == .Class

감사. 그것이 나를 위해 일한 것입니다. 유일한 것은 (iOS 9 이상에서) subjectType이 ".Type"으로 끝나는 것이므로 문자열에서 해당 부분을 제거해야했습니다.
Nikolay Suvandzhiev

8

스위프트 5.1

그래도 클래스, 구조체, 열거 형, 프로토콜 및 NSObject 이름을 얻을 수 있습니다 Self.self.

print("\(Self.self)")

참고 이는 모듈 이름 (다르게에 붙일 수 있음 String(describing: type(of: self)))
IXX

7

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

6

다음 NSObjectProtocol과 같이 Swift 4에서 확장 할 수 있습니다 .

import Foundation

extension NSObjectProtocol {

    var className: String {
        return String(describing: Self.self)
    }
}

이렇게하면 계산 된 변수 className를 모든 클래스에서 사용할 수 있습니다. print()in 내부에서 이것을 사용하면 콘솔에서 CalendarViewController인쇄 "CalendarViewController"됩니다.


4

나는이 답변을 잠시 동안 찾고있었습니다. 나는 GKStateMachine을 사용하고 상태 변경을 관찰하고 클래스 이름 만 쉽게 볼 수있는 방법을 원했습니다. iOS 10 또는 Swift 2.3인지 확실하지 않지만 해당 환경에서 다음은 정확히 내가 원하는 것을 수행합니다.

let state:GKState?
print("Class Name: \(String(state.classForCoder)")

// Output:    
// Class Name: GKState

4

클래스의 이름을 다음과 같이 할 수 있습니다.

class Person {}
String(describing: Person.self)

3

클래스 이름을 문자열로 얻으려면 다음과 같이 클래스를 선언하십시오.

@objc(YourClassName) class YourClassName{}

다음 구문을 사용하여 클래스 이름을 얻습니다.

NSStringFromClass(YourClassName)

3

reflect().summary클래스 자체 또는 인스턴스 dynamicType을 사용해보십시오 . 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;
}

3

위의 솔루션은 저에게 효과적이지 않았습니다. 대부분의 문제는 여러 의견에서 언급되었습니다.

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

2

Swift 3.0 (macOS 10.10 이상), className에서 얻을 수 있습니다

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

1
내가 알 수있는 한 Swift 클래스에는 내장 className 속성이 없습니다. 당신은 무언가에서 서브 클래스를 했습니까?
shim

@shim className은 Foundation에서 선언되었지만 macOS 10.10 이상에서만 사용할 수있는 것 같습니다. 방금 답변을 편집했습니다.
Thanh Vũ Trần

1
흠, 이상해. iOS에 왜 포함시키지 않습니까? 또한 NSObject developer.apple.com/reference/objectivec/nsobject/…
shim

2

type(of:...)Swift 3으로 놀이터에서 시도 했습니다. 이것이 나의 결과입니다. 이것은 코드 형식 버전입니다.

print(String(describing: type(of: UIButton.self)))
print(String(describing: type(of: UIButton())))
UIButton.Type
UIButton

클래스 이름을 결정하기 위해 인스턴스를 인스턴스화하는 것은 낭비입니다.
sethfri

@sethfri 나는 이것을 사용하여 동적 유형을 결정합니다.
Lumialxk

당신은 단지 클래스의 타입 정보를 얻기 위해 인스턴스를 생성해야하는 이유 난 아직도 이해가 안 돼요
sethfri


2

var 클래스에 대한 이런 종류의 예제입니다. 번들 이름을 포함하지 마십시오.

extension NSObject {
    class var className: String {
        return "\(self)"
    }
}

1

맹 글링 된 이름이 마음에 들지 않으면 자신의 이름을 지정할 수 있습니다.

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

그러나 장기적으로 맹 글링 된 이름을 구문 분석하는 방법을 배우는 것이 좋습니다. 형식은 표준적이고 의미가 있으며 변경되지 않습니다.


아닙니다. 내 클래스의 경우 (ExistentialMetatype)을 반환합니다. 언급되지 않은 런타임 동작에 의존하는 것은 항상 위험합니다. 특히 여전히 비교적 초기 단계이기 때문에 신속합니다.
superarts.org

1

때로는 다른 솔루션에서 보려는 객체에 따라 유용한 이름이 아닌 경우가 있습니다. 이 경우 다음을 사용하여 클래스 이름을 문자열로 얻을 수 있습니다.

String(cString: object_getClassName(Any!))

⌘ xcode에서 함수를 클릭하면 매우 유용한 관련 방법을 볼 수 있습니다. 또는 여기에서 확인하십시오 https://developer.apple.com/reference/objectivec/objective_c_functions


1

Swift 5 String 을 사용하여 class_name을 문자열로 얻을 수 있습니다 (설명 : Self.self)

print(String(describing: Self.self))

0

Swift 2.2에서 사용합니다

guard let currentController = UIApplication.topViewController() else { return }
currentController.classForCoder.description().componentsSeparatedByString(".").last!

0

스위프트 5.1 :-

객체의 클래스 이름을 문자열로 얻기 위해 일반 함수를 사용할 수도 있습니다

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

}

다음을 사용하여이 함수를 호출하십시오.

let name = GenericFunctions.className(ViewController.self)

행복한 코딩 :)


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.