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

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

object_getClassName(myViewController)

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

_TtC5AppName22CalendarViewController

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

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



답변

인스턴스의 문자열 :

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.


답변

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)

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


답변

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


답변

스위프트 3.0

String(describing: MyViewController.self)


답변

나는 그런 접근 방식을 제안합니다 ( 매우 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


답변

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


답변

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