web-dev-qa-db-ja.com

(Swiftで)オブジェクトの種類をどのように見つけますか?

プログラムを理解しようとするとき、あるいはいくつかの稀なケースでは、何かタイプが何かを実際に見つけることができると便利です。私はデバッガがあなたに何らかの型情報を見せることができることを知っています、そしてあなたはたいていそれらの状況で型を指定しないことをやめるために型推論に頼ることができます、それでも、私は本当にPythonのtype()のようなものが欲しいです

dynamicType(この質問を参照してください)

更新:これはSwiftの最近のバージョンで変更されました。obj.dynamicTypeは動的型のインスタンスではなく型への参照を与えるようになりました。

これは最も有望であるように思われます、しかし今のところ私は実際のタイプを見つけることができませんでした

class MyClass {
    var count = 0
}

let mc = MyClass()

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

また、クラス参照を使用して新しいオブジェクトをインスタンス化しようとしました。これはdoesworkですが、requiredイニシャライザを追加する必要があるというエラーが表示されました。

動作します:

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

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

それでも、与えられたオブジェクトの種類を実際に発見するためのほんの小さなステップ

edit:あまり関係のない詳細をかなり削除しました - 興味があれば編集履歴を見てください:)

234
Jiaaro

Swift 3バージョン:

type(of: yourObject)
236

Swift 2.0では、このようなタイプのイントロスペクションを行うための適切な方法は、 Mirror struct を使用することです。

    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!")
    }
106
Gudbergur

"dynamicType.printClassName"コードはSwiftの本の例からのものです。カスタムクラス名を直接取得する方法はありませんが、次に示すように "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()
58
Dash

Xcode 6.0.1以降(少なくとも、いつ追加されたのかわからない)、元の例は正常に動作するようになりました。

class MyClass {
    var count = 0
}

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

更新:

元の質問に答えるために、あなたは実際に普通のSwiftオブジェクトでObj-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))
41
Alex Pretzlav

変数がX型であるかどうか、または何らかのプロトコルに準拠しているかどうかを確認するだけの場合は、次のようにisまたはas?を使用できます。

var unknownTypeVariable = …

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

これはObj-CのisKindOfClassと同等です。

そしてこれは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>
}
35
Valerii Lider

これはSwift 3で動作します

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

ここに私がそれをすることをお勧めする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")
}
8
Esqarrouth

Swift 3.0の場合

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

Swift 2.0の場合 - 2.3

String(<Class-Name>)
6
techloverr

ユースケースに依存します。しかし、あなたがあなたの "変数"型に対して何か有用なことをしたいと仮定しましょう。 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()メソッドでは、値が正しくテストされていることを確認する必要があります。文字列などの場合はStringだけをテストする必要があります。switchステートメントを使用すると、これが簡単かつ安全になります。 Any型の変数に9を代入することで、Int用スイッチを実行します。それを変更してみてください。

   let eValue:Any = "home9"

..もう一度やり直してください。今回はas Stringケースを実行します。

1
CPD
//: 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
0
Avi Cohen

「常に真/失敗」という警告が表示される場合は、isを使用する前にAnyにキャストする必要があります。

(foo as Any) is SomeClass
0
josef