(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 2014年

@Davidは同様ですが、すべての変数がクラスインスタンスであるとは限りません。また、その質問は、型がプログラマーが探しているものと一致するかどうかを確認することに関するものでしたが、型の卸売りを見つけたいと思っています
Jiaaro


回答:


284

Swift 3バージョン:

type(of: yourObject)

8
楽しい事実。これは暗黙的にアンラップされたオプションでは機能しません!すなわちvar myVar: SomeType!。コンパイラーは、「タイプ 'SomeType!.Type'(別名 'ImplicitlyUnwrappedOptional <SomeType> .Type')の値を予期される引数タイプ 'AnyClass'(別名 'AnyObject.Type')に変換できません。コンパイラーはas! AnyClass、タイプの後に追加することを提案しますが、一部の「EXC_BAD_INSTRUCTION」や解読できないその他のイベリッシュでプログラムがクラッシュする
LightningStryk

1
実際、Swift 3が存在するようになった今、これは受け入れられる答えになるはずです。ジェレミーありがとう!
biomiker

1
特定のタイプ名を探している場合、タイプがプロトコルタイプの場合、これは機能しない可能性があります。
Chris Prince

2
お持ちの場合はStringタイプとして渡されたことAny、その後type(of:)の意志出力Any、ありませんString
ScottyBlades

1
@ScottyBladesなので、解決策は何でしょうか。提供できますか?
Mubin Mall

109

Swift 2.0:

このようなタイプのイントロスペクションを行う適切な方法は、ミラー構造体を使用することです

    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、2015年

1
まさに私が探していたもの、オブジェクトの種類が何かを知りたい
ジョセフ

このコンテキストで、オプション型と非オプション型を比較するときに失敗ないタイプの比較はありますか?
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が指摘したように、動作が変更されました。
ジアアロ2014年

1
はい。Swift 3.0以降、subjectTypeは使用できなくなりdynamicType、コンパイラーから非推奨メッセージが出されます。
ラファエル

41

以下のようXcodeの6.0.1(少なくとも、ではない彼らはそれを追加したとき)、あなたの元の例が動作するようになりました:

class MyClass {
    var count = 0
}

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

更新:

元の質問に答えるために、プレーンSwiftオブジェクトでObjective-Cランタイムを実際に使用できます。

以下を試してください:

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

インスタンスではなくタイプを与えるように変更したようです。
ジアアロ2014年

@ジャアロ、私はあなたの元の質問であなたが探していたと私が思うことで私の回答を更新しました
アレックスプレッツラフ

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

答えの2番目の部分は間違っています。as?条件付きキャストの 'if let'ステートメントも同じように動作し、isKindOfClass成功した場合のキャストの結果も提供します。
awolf 2016年

に相当するのisMemberOfClassは条件object.dynamicType == ClassName.selfです。
awolf 2016年


10

Swift 3.0の場合

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

Swift 2.0-2.3の場合

String(<Class-Name>)

1
この答えが私にとって正しいことの重要なことは、結果の文字列がクラス名と正確に一致することです。これを使用して、NSManagedObjectサブクラスからCore Dataエンティティ名を取得できます。Swift3版を使用しました。
Kendall Helmstetter Gelner 2017

8

ここに私がそれを行うことをお勧めする2つの方法があります:

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 2016年

オブジェクトのタイプを取得するための良い解決策。
nihasmata 2018

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

「常にtrue /失敗する」という警告が表示された場合は、使用する前に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.