Swift에서 객체의 유형을 어떻게 알 수 있습니까?


255

프로그램이나 일부 경우를 이해하려고 할 때 실제로 어떤 유형인지 알아내는 것이 유용합니다. 디버거가 일부 유형 정보를 표시 할 수 있다는 것을 알고 있으며 일반적으로 유형 유추에 의존하여 해당 상황에서 유형을 지정하지 않아도 될 수는 있지만 여전히 Python과 같은 것을 원합니다.type()

dynamicType ( 이 질문 참조 )

업데이트 : 이것은 최신 버전의 Swift에서 변경되었으며 obj.dynamicType이제 동적 유형의 인스턴스가 아닌 유형에 대한 참조를 제공합니다.

이것은 가장 유망한 것으로 보이지만 지금까지 실제 유형을 찾을 수 없었습니다.

class MyClass {
    var count = 0
}

let mc = MyClass()

# update: this now evaluates as true
mc.dynamicType === MyClass.self

또한 새로운 객체 인스턴스화하는 클래스 참조를 사용하여 시도 하지 작업을하지만, 이상하게 나에게 내가 추가해야합니다라는 오류 준 required이니셜 라이저 :

공장:

class MyClass {
    var count = 0
    required init() {
    }
}

let myClass2 = MyClass.self
let mc2 = MyClass2()

그래도 주어진 객체의 유형을 실제로 발견하는 작은 단계 만 있습니다.

편집 : 나는 지금 관련이없는 많은 세부 사항을 제거했습니다. 관심이 있다면 편집 기록을보십시오 :)



1
흥미롭게도 print(mc)또는 어딘가에 클래스 이름이 포함 dump(mc)된 요약 ( toString(mc)또는 에서 가져올 수 있음 reflect(mc).summary) 을 인쇄합니다 . 그러나 클래스 이름을 직접 얻는 방법은 명확하지 않습니다.
newacct

@David와 비슷하지만 모든 변수가 클래스 인스턴스는 아닙니다. 또한 그 질문은 타입이 프로그래머가 찾고있는 것과 일치하는지 확인하는 것에 관한 것이지만, 나는 타입 도매를 찾기를 바라고 있습니다
Jiaaro


답변:


284

스위프트 3 버전 :

type(of: yourObject)

8
재미있는 사실. 암시 적으로 래핑되지 않은 옵션과는 작동하지 않습니다! 즉 var myVar: SomeType!. 컴파일러 (일명 'ImplicitlyUnwrappedOptional <SomeType> .Type') 예상 인수 유형 'AnyClass'(일명 'AnyObject.Type') 컴파일러에 추가 할 것을 제안 형 'SomeType! .Type를'값을 변환 할 수 없습니다 오류 "를 제공 as! AnyClass한 후 유형하지만 이후 프로그램이 일부 "EXC_BAD_INSTRUCTION"및 기타 해독 할 수없는 충돌과 충돌합니다
LightningStryk

1
실제로, 이것은 스위프트 3이 존재하기 때문에 이제 받아 들여질만한 대답이어야합니다. 제레미 감사합니다!
biomiker

1
특정 유형 이름을 찾는 경우 유형이 프로토콜 유형 인 경우에는 작동하지 않을 수 있습니다.
Chris Prince

2
당신이있는 경우 String유형으로 전달되는 그 Any다음 type(of:)의지를 출력 Any하지 String.
ScottyBlades

1
@ScottyBlades 그래서 솔루션이 될 것입니다. 제공 할 수 있습니까?
Mubin Mall

109

스위프트 2.0 :

이런 종류의 유형 내성 검사를 수행하는 올바른 방법은 Mirror 구조체를 사용하는 것입니다 .

    let stringObject:String = "testing"
    let stringArrayObject:[String] = ["one", "two"]
    let viewObject = UIView()
    let anyObject:Any = "testing"

    let stringMirror = Mirror(reflecting: stringObject)
    let stringArrayMirror = Mirror(reflecting: stringArrayObject)
    let viewMirror = Mirror(reflecting: viewObject)
    let anyMirror = Mirror(reflecting: anyObject)

그런 다음 Mirror 구조체subjectType 과 같이 속성을 사용하십시오 .

    // Prints "String"
    print(stringMirror.subjectType)

    // Prints "Array<String>"
    print(stringArrayMirror.subjectType)

    // Prints "UIView"
    print(viewMirror.subjectType)

    // Prints "String"
    print(anyMirror.subjectType)

그런 다음 다음과 같은 것을 사용할 수 있습니다.

    if anyMirror.subjectType == String.self {
        print("anyObject is a string!")
    } else {
        print("anyObject is not a string!")
    }

7
대단하다. 미러링되는 개체가 선택적인 유형 인 경우 선택 사항이 아닌 유형과 비교할 수 없습니다. StringOptional(String)동일하지 않습니다.
Thomas Verbeek

1
정확히 내가 찾던 것은 물체의 유형이 무엇인지 알고 싶었습니다
Joseph

이 문맥에서 선택 사항을 선택 사항이 아닌 유형과 비교할 때 실패하지 않는 비교 유형이 있습니까?
Chris Prince

그것이 내가 찾던 것입니다. @Gudbergur 감사합니다.
Mubin Mall

60

dynamicType.printClassName코드는 스위프트 책의 예에서입니다. 사용자 정의 클래스 이름을 직접 얻는 방법은 없지만 is아래 표시된 키워드를 사용하여 인스턴스 유형을 확인할 수 있습니다. 이 예제는 또한 클래스 이름을 문자열로 원하는 경우 사용자 정의 className 함수를 구현하는 방법도 보여줍니다.

class Shape {
    class func className() -> String {
        return "Shape"
    }
}

class Square: Shape {
    override class func className() -> String {
        return "Square"
    }
}

class Circle: Shape {
    override class func className() -> String {
        return "Circle"
    }
}

func getShape() -> Shape {
    return Square() // hardcoded for example
}

let newShape: Shape = getShape()
newShape is Square // true
newShape is Circle // false
newShape.dynamicType.className() // "Square"
newShape.dynamicType.className() == Square.className() // true

참고 :
하위 클래스는 NSObject이미 자체 className 함수를 구현합니다. Cocoa를 사용하는 경우이 속성을 사용하면됩니다.

class MyObj: NSObject {
    init() {
        super.init()
        println("My class is \(self.className)")
    }
}
MyObj()

2
이봐, 언제 바뀌 었는지 확실하지 않지만 Alex Pretzlav가 지적했듯이 행동이 바뀌 었습니다.
Jiaaro

1
예. Swift 3.0 부터는 subjectType더 이상 사용할 수 없으며 dynamicType컴파일러에서 지원 중단 메시지가 표시됩니다.
Raphael

41

현재 엑스 코드 6.0.1 (그들이 그것을 추가 할 때 적어도하지 않도록), 원래의 예는 이제 작동합니다 :

class MyClass {
    var count = 0
}

let mc = MyClass()
mc.dynamicType === MyClass.self // returns `true`

최신 정보:

원래 질문에 대답하기 위해 실제로 Objective-C 런타임을 일반 Swift 객체와 함께 성공적으로 사용할 수 있습니다.

다음을 시도하십시오 :

import Foundation
class MyClass { }
class SubClass: MyClass { }

let mc = MyClass()
let m2 = SubClass()

// Both of these return .Some("__lldb_expr_35.SubClass"), which is the fully mangled class name from the playground
String.fromCString(class_getName(m2.dynamicType))
String.fromCString(object_getClassName(m2))
// Returns .Some("__lldb_expr_42.MyClass")
String.fromCString(object_getClassName(mc))

인스턴스 대신 유형을 제공하기 위해 변경 한 것 같습니다.
Jiaaro

@Jiaaro, 나는 당신이 당신의 원래 질문에서 찾고 있다고 생각하는 것으로 내 대답을 업데이트했습니다
Alex Pretzlav

36

변수가 X 유형인지 또는 일부 프로토콜을 준수하는지 여부를 확인 해야하는 경우 is, 또는 as?다음과 같이 사용할 수 있습니다 .

var unknownTypeVariable =if unknownTypeVariable is <ClassName> {
    //the variable is of type <ClassName>
} else {
    //variable is not of type <ClassName>
}

이것은 isKindOfClassObj-C 와 동일 합니다.

그리고 이것은 conformsToProtocol또는isMemberOfClass

var unknownTypeVariable =if let myClass = unknownTypeVariable as? <ClassName or ProtocolName> {
    //unknownTypeVarible is of type <ClassName or ProtocolName>
} else {
    //unknownTypeVariable is not of type <ClassName or ProtocolName>
}

답의 두 번째 부분이 잘못되었습니다. as?조건부 캐스트가있는 'if let'문도 마찬가지로 동일하게 수행 isKindOfClass되며 캐스트가 성공하면 캐스트 결과도 제공합니다.
awolf

isMemberOfClass조건은 다음과 같습니다 object.dynamicType == ClassName.self.
awolf

18

스위프트 3 :

if unknownType is MyClass {
   //unknownType is of class type MyClass
}

스위프트 3 이전is 부터 존재 한다고 생각 합니까?
Nicolas Miari

10

스위프트 3.0

String(describing: <Class-Name>.self)

스위프트 2.0-2.3

String(<Class-Name>)

1
이 답변에 대한 중요한 점은 결과 문자열이 클래스 이름과 정확히 일치한다는 것입니다. 따라서 NSManagedObject 하위 클래스에서 Core Data 엔터티 이름을 가져올 수 있습니다. Swift3 버전을 사용했습니다.
Kendall Helmstetter Gelner

8

추천하는 두 가지 방법이 있습니다.

if let thisShape = aShape as? Square 

또는:

aShape.isKindOfClass(Square)

자세한 예는 다음과 같습니다.

class Shape { }
class Square: Shape { } 
class Circle: Shape { }

var aShape = Shape()
aShape = Square()

if let thisShape = aShape as? Square {
    println("Its a square")
} else {
    println("Its not a square")
}

if aShape.isKindOfClass(Square) {
    println("Its a square")
} else {
    println("Its not a square")
}

2
print( aShape is Square ), is연산자가 더 바람직합니다.
DawnSong

객체 유형을 얻는 좋은 해결책입니다.
nihasmata

1

사용 사례에 따라 다릅니다. 그러나 "가변"유형에 유용한 무언가를 원한다고 가정 해 봅시다. Swift switch문은 매우 강력하며 원하는 결과를 얻는 데 도움이 될 수 있습니다 ...

    let dd2 = ["x" : 9, "y" : "home9"]
    let dds = dd2.filter {
        let eIndex = "x"
        let eValue:Any = 9
        var r = false

        switch eValue {
        case let testString as String:
            r = $1 == testString
        case let testUInt as UInt:
            r = $1 == testUInt
        case let testInt as Int:
            r = $1 == testInt
        default:
            r = false
        }

        return r && $0 == eIndex
    }

이 경우 UInt, Int 또는 String이 될 수있는 키 / 값 쌍이 포함 된 간단한 사전이 있어야합니다. .filter()사전 의 메소드에서 값을 올바르게 테스트하고 문자열 등의 경우에만 문자열을 테스트해야합니다. switch 문은 이것을 간단하고 안전하게 만듭니다! Any 유형의 변수에 9를 지정하면 Int 스위치가 실행됩니다. 다음과 같이 변경하십시오.

   let eValue:Any = "home9"

.. 그리고 다시 시도하십시오. 이번에는 as String사례를 실행합니다 .


1

"항상 참 / 실패"경고가 표시되면 사용하기 전에 Any로 전송해야 할 수 있습니다. is

(foo as Any) is SomeClass

0
//: Playground - noun: a place where people can play

import UIKit

class A {
    class func a() {
        print("yeah")
    }

    func getInnerValue() {
        self.dynamicType.a()
    }
}

class B: A {
    override class func a() {
        print("yeah yeah")
    }
}

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