Swiftで変数の型またはクラスを出力するにはどうすればよいですか?


335

変数のランタイム型を迅速に出力する方法はありますか?例えば:

var now = NSDate()
var soon = now.dateByAddingTimeInterval(5.0)

println("\(now.dynamicType)") 
// Prints "(Metatype)"

println("\(now.dynamicType.description()")
// Prints "__NSDate" since objective-c Class objects have a "description" selector

println("\(soon.dynamicType.description()")
// Compile-time error since ImplicitlyUnwrappedOptional<NSDate> has no "description" method

上記の例では、変数「soon」のタイプがImplicitlyUnwrappedOptional<NSDate>少なくともであることを示す方法を探していますNSDate!


43
@JasonMArcherリンクした質問がこの質問の4日後に行われた場合、これはどのように重複しているのか教えてください。
akashivskyy 14年

SwiftオブジェクトのタイプのテストまたはSwiftオブジェクトのタイプの読み取りについては、いくつかの質問があります。このテーマの「マスター」質問として使用するのに最適な質問を見つけています。提案された複製には、より完全な答えがあります。これは、あなたが何か間違ったことをしたと言っているのではなく、単に混乱を減らしようとしているだけです。
JasonMArcher 14年

4
提案された複製は同じ質問に答えていません。Type.selfは、デバッグの目的でコンソールに出力することはできません。Typesをオブジェクトとして受け取る他の関数に渡すために使用するためのものです。
Matt Bridges

2
OT:Swiftがそのままではそれを提供しないことは非常に奇妙であり、そのような低レベルのCライブラリをいじる必要があります。バグレポートに値する?
qwerty_so 2014年

皆さん、私は以下に私の答えを提供しました。どうぞご期待ください。
DILIP KOSURI 2017

回答:


377

2016年9月更新

スウィフト3.0:使用type(of:)、例えばtype(of: someThing)(以降dynamicTypeキーワードが削除されています)

2015年10月の更新

私は新しいスウィフト2.0構文に以下の例を更新しました(例えばprintln置換した後printtoString()今ありますString())。

Xcode 6.3リリースノートから

@nschumは、コメントの中でXcode 6.3リリースノートが別の方法を示していることを指摘しています。

型の値は、printlnまたは文字列補間で使用すると、完全なデマングルタイプ名として印刷されるようになりました。

import Foundation

class PureSwiftClass { }

var myvar0 = NSString() // Objective-C class
var myvar1 = PureSwiftClass()
var myvar2 = 42
var myvar3 = "Hans"

print( "String(myvar0.dynamicType) -> \(myvar0.dynamicType)")
print( "String(myvar1.dynamicType) -> \(myvar1.dynamicType)")
print( "String(myvar2.dynamicType) -> \(myvar2.dynamicType)")
print( "String(myvar3.dynamicType) -> \(myvar3.dynamicType)")

print( "String(Int.self)           -> \(Int.self)")
print( "String((Int?).self         -> \((Int?).self)")
print( "String(NSString.self)      -> \(NSString.self)")
print( "String(Array<String>.self) -> \(Array<String>.self)")

どの出力:

String(myvar0.dynamicType) -> __NSCFConstantString
String(myvar1.dynamicType) -> PureSwiftClass
String(myvar2.dynamicType) -> Int
String(myvar3.dynamicType) -> String
String(Int.self)           -> Int
String((Int?).self         -> Optional<Int>
String(NSString.self)      -> NSString
String(Array<String>.self) -> Array<String>

Xcode 6.3の更新:

あなたは使うことができます_stdlib_getDemangledTypeName()

print( "TypeName0 = \(_stdlib_getDemangledTypeName(myvar0))")
print( "TypeName1 = \(_stdlib_getDemangledTypeName(myvar1))")
print( "TypeName2 = \(_stdlib_getDemangledTypeName(myvar2))")
print( "TypeName3 = \(_stdlib_getDemangledTypeName(myvar3))")

これを出力として取得します。

TypeName0 = NSString
TypeName1 = __lldb_expr_26.PureSwiftClass
TypeName2 = Swift.Int
TypeName3 = Swift.String

元の答え:

Xcode 6.3より前_stdlib_getTypeNameのバージョンでは、変数のマングル型名が取得されていました。Ewan Swickのブログエントリは、これらの文字列を解読するのに役立ちます。

たとえば_TtSi、Swiftの内部Intタイプを表します。

マイク・アッシュは、同じトピックをカバーする素晴らしいブログエントリを持っています


2
どのようにして見つけました_stdlib_getTypeName()か?統合されたREPLはもはや存在swift-ide-testせず、存在もせず、SwiftモジュールのXcodeによる出力は、接頭_辞付きの値を省略します。
リリーバラード

10
lldbreplで十分簡単にシンボルを検索できるようです。_stdlib_getDemangledTypeName()ともあり_stdlib_demangleName()ます。
リリーバラード

1
ああ、すっかり、imageのショートカットだとは知りませんでしたtarget modules。最終的にはを使用することtarget modules lookup -r -n _stdlib_になりましたが、もちろん次のように表現されますimage lookup -r -n _stdlib_ libswiftCore.dylib
リリーバラード14

1
FYI-toString(...)はString(...)に置き換えられたようです。
Nick

6
Swift 3.0:dynamicTypeキーワードはSwiftから削除されました。その代わりに、新しいプリミティブ関数type(of:)が言語に追加されました:github.com/apple/swift/blob/master/CHANGELOG.md
Szu

46

編集:Swift 1.2(Xcode 6.3)に新しいtoString関数が導入されました

次を使用して.self、任意のタイプおよび任意のインスタンスのデマングルタイプを印刷できるようになりました.dynamicType

struct Box<T> {}

toString("foo".dynamicType)            // Swift.String
toString([1, 23, 456].dynamicType)     // Swift.Array<Swift.Int>
toString((7 as NSNumber).dynamicType)  // __NSCFNumber

toString((Bool?).self)                 // Swift.Optional<Swift.Bool>
toString(Box<SinkOf<Character>>.self)  // __lldb_expr_1.Box<Swift.SinkOf<Swift.Character>>
toString(NSStream.self)                // NSStream

呼び出してみてくださいYourClass.selfyourObject.dynamicType

リファレンス:https : //devforums.apple.com/thread/227425


2
そのスレッドに返信しましたが、ここにコメントを追加します。これらの値のタイプは「メタタイプ」ですが、メタタイプオブジェクトが表すタイプを簡単に判別する方法はないようです。これが私が探しているものです。
Matt Bridges

それらはメタタイプであり、クラスです。それらはクラスを表します。あなたの問題が何であるか正確にわかりません。someInstance.dynamicType.printClassName()クラスの名前を出力します。
アナログファイル

18
printClassName()メソッドは、ドキュメントのサンプルの1つで作成したメソッドの例にすぎず、アクセスできるAPI呼び出しではありません。
Dave Wood

4
FYI-toString(...)はString(...)に置き換えられたようです
Nick

33

Swift 3.0

let string = "Hello"
let stringArray = ["one", "two"]
let dictionary = ["key": 2]

print(type(of: string)) // "String"

// Get type name as a string
String(describing: type(of: string)) // "String"
String(describing: type(of: stringArray)) // "Array<String>"
String(describing: type(of: dictionary)) // "Dictionary<String, Int>"

// Get full type as a string
String(reflecting: type(of: string)) // "Swift.String"
String(reflecting: type(of: stringArray)) // "Swift.Array<Swift.String>"
String(reflecting: type(of: dictionary)) // "Swift.Dictionary<Swift.String, Swift.Int>"

1
Swift 2の実装は、列挙型の場合に特に優れています。この動作がAppleによって文書化/保証されているかどうか誰かが知っていますか?標準ライブラリには、これがデバッグに適しているというコメントが含まれています...
milos

30

これはあなたが探しているものですか?

println("\(object_getClassName(now))");

「__NSDate」を出力します

更新:これはBeta05の時点では機能していないようです。


2
迅速なクラスでは機能しません。「UnsafePointer(0x7FBB18D06DE0)」を返します
aryaxt

4
ObjCクラスでも機能しません(少なくともBeta5では)。NSManagedObjectの場合、「Builtin.RawPointer = address」を取得します
Kendall Helmstetter Gelner

23

私の現在のXcodeはバージョン6.0(6A280e)です。

import Foundation

class Person { var name: String; init(name: String) { self.name = name }}
class Patient: Person {}
class Doctor: Person {}

var variables:[Any] = [
    5,
    7.5,
    true,
    "maple",
    Person(name:"Sarah"),
    Patient(name:"Pat"),
    Doctor(name:"Sandy")
]

for variable in variables {
    let typeLongName = _stdlib_getDemangledTypeName(variable)
    let tokens = split(typeLongName, { $0 == "." })
    if let typeName = tokens.last {
        println("Variable \(variable) is of Type \(typeName).")
    }
}

出力:

Variable 5 is of Type Int.
Variable 7.5 is of Type Double.
Variable true is of Type Bool.
Variable maple is of Type String.
Variable Swift001.Person is of Type Person.
Variable Swift001.Patient is of Type Patient.
Variable Swift001.Doctor is of Type Doctor.

1
良いですが、質問にはオプションも含まれています。オプションの出力はで設定されるOptional(...)ため、コードはOptionalタイプとしてのみ返されます。またvar optionalTestVar: Person? = Person(name:"Sarah")、Optional(Person)およびvar with Personとして表示されます。ImplicitlyUnwrappedOptional(Person)
Binarian

18

Xcode 6.3とSwift 1.2では、単純に型の値を完全なデマングルに変換できますString

toString(Int)                   // "Swift.Int"
toString(Int.Type)              // "Swift.Int.Type"
toString((10).dynamicType)      // "Swift.Int"
println(Bool.self)              // "Swift.Bool"
println([UTF8].self)            // "Swift.Array<Swift.UTF8>"
println((Int, String).self)     // "(Swift.Int, Swift.String)"
println((String?()).dynamicType)// "Swift.Optional<Swift.String>"
println(NSDate)                 // "NSDate"
println(NSDate.Type)            // "NSDate.Type"
println(WKWebView)              // "WKWebView"
toString(MyClass)               // "[Module Name].MyClass"
toString(MyClass().dynamicType) // "[Module Name].MyClass"

1.2で他の方向は可能ですか?クラス名に基づいてインスタンスを初期化するには?
user965972

@ user965972私の知る限りではないと思います。
2015

17

className(を返すString)を介してクラスにアクセスできます。

例えば、クラスを取得するにはいくつかの方法、実際に存在するclassForArchiverclassForCoderclassForKeyedArchiver(すべてのリターンがAnyClass!)。

プリミティブのタイプを取得することはできません(プリミティブはクラスではありません)。

例:

var ivar = [:]
ivar.className // __NSDictionaryI

var i = 1
i.className // error: 'Int' does not have a member named 'className'

プリミティブのタイプを取得したい場合は、を使用する必要がありますbridgeToObjectiveC()。例:

var i = 1
i.bridgeToObjectiveC().className // __NSCFNumber

私はそれが原始的であるに違いない。残念ながら、プリミティブのタイプを取得することはできません。
Leandros、2014年

これらの例は、遊び場では機能しないようです。プリミティブと非プリミティブの両方でエラーが発生します。
Matt Bridges

してみてくださいimport Cocoa
Leandros、2014年

9
classNameは、OSX向けに開発しているときにNSObjectsでのみ使用できるようです。iOS SDKでは、NSObjectsまたは「通常の」オブジェクトのいずれにも使用できません
Matt Bridges

3
classNameCocoaのAppleScriptサポートの一部であり、一般的なイントロスペクションには使用しないでください。明らかに、iOSでは利用できません。
Nikolai Ruhe 2014

16

リフレクトを使用して、オブジェクトに関する情報を取得できます。
たとえば、オブジェクトクラスの名前:

var classname = Reflect(now).summary

Beta 6では、これにより、アプリ名+クラス名が少し複雑な形で表示されましたが、それは始まりです。+1- reflect(x).summaryありがとう!
Olie

動作しませんでした、Swift 1.2 Xcode 6.4およびiOs 8.4で空白行を印刷します
Juan Boero

13

私は運が良かった:

let className = NSStringFromClass(obj.dynamicType)

@hdost男は何もうまくいきませんでしたが、classForCoderは働きました。
Satheeshwaran 2015


10

Xcode 8では、Swift 3.0

手順:

1.タイプを取得します。

オプション1:

let type : Type = MyClass.self  //Determines Type from Class

オプション2:

let type : Type = type(of:self) //Determines Type from self

2.タイプを文字列に変換します。

let string : String = "\(type)" //String


7

スイフト5

Swift 3の最新リリースでは、String初期化子を介して型名のかなりの説明を取得できます。例えば、同様print(String(describing: type(of: object)))。どこにobject インスタンス変数ことができ、配列、辞書などIntNSDateカスタムクラスのインスタンスなど

これが私の完全な答えです:Swiftでオブジェクトのクラス名を文字列として取得します

その質問は、オブジェクトのクラス名を文字列として取得する方法を探していますが、のサブクラスではない変数のクラス名を取得する別の方法も提案しましたNSObject。ここにあります:

class Utility{
    class func classNameAsString(obj: Any) -> String {
        //prints more readable results for dictionaries, arrays, Int, etc
        return String(describing: type(of: obj))
    }
}

型のオブジェクトをパラメーターとして受け取り、Anyそのクラス名をString:) として返す静的関数を作成しました。

私はこの関数を次のようないくつかの変数でテストしました:

    let diccionary: [String: CGFloat] = [:]
    let array: [Int] = []
    let numInt = 9
    let numFloat: CGFloat = 3.0
    let numDouble: Double = 1.0
    let classOne = ClassOne()
    let classTwo: ClassTwo? = ClassTwo()
    let now = NSDate()
    let lbl = UILabel()

そして出力は:

  • 辞書はタイプ辞書です
  • 配列のタイプは配列です
  • numIntはInt型です
  • numFloatはCGFloat型です
  • numDoubleはDouble型です
  • classOneのタイプ:ClassOne
  • classTwoのタイプ:ClassTwo
  • 現在のタイプは次のとおりです:日付
  • lblのタイプ:UILabel

5

Cocoaを使用する場合(CocoaTouchではない)、classNameNSObjectのサブクラスであるオブジェクトのプロパティを使用できます。

println(now.className)

このプロパティは、NSObjectのサブクラスではない通常のSwiftオブジェクトでは使用できません(実際、SwiftにはルートIDまたはオブジェクトタイプはありません)。

class Person {
    var name: String?
}

var p = Person()
println(person.className) // <- Compiler error

CocoaTouchでは、現時点では、特定の変数の型の文字列記述を取得する方法はありません。CocoaまたはCocoaTouchのプリミティブ型には、同様の機能はありません。

Swift REPLは、そのタイプを含む値の要約を出力できるため、将来的には、この方法でAPIを介してイントロスペクションを行うことができる可能性があります。

編集dump(object)トリックを行うようです。


Xcode 10とSwift 4.2でも、dump(object)非常に強力です。ありがとうございました。
Alex Zavatone

5

上の答えには、を使用してこれを行う新しい方法の実用的な例がありませんtype(of:。私のような新人を助けるために、ここに主にAppleのドキュメントから取られた実用的な例があります-https://developer.apple.com/documentation/swift/2885064-type

doubleNum = 30.1

func printInfo(_ value: Any) {
    let varType = type(of: value)
    print("'\(value)' of type '\(varType)'")
}

printInfo(doubleNum)
//'30.1' of type 'Double'

4

私はここで他のいくつかの答えを試しましたが、走行距離は下にあるオブジェクトが何であるかに非常に似ているようです。

ただし、次のようにしてオブジェクトのObject-Cクラス名を取得する方法を見つけました。

now?.superclass as AnyObject! //replace now with the object you are trying to get the class name for

次に、使用方法の例を示します。

let now = NSDate()
println("what is this = \(now?.superclass as AnyObject!)")

この場合、コンソールにNSDateが出力されます。


4

うまくいけば他の誰かのために働くかもしれないこの解決策を見つけました。値にアクセスするクラスメソッドを作成しました。これはNSObjectサブクラスでのみ機能することを覚えておいてください。しかし、少なくともクリーンで整頓されたソリューションです。

class var className: String!{
    let classString : String = NSStringFromClass(self.classForCoder())
    return classString.componentsSeparatedByString(".").last;
}

4

Swift 1.2を搭載した最新のXCode 6.3では、これが私が見つけた唯一の方法です。

if view.classForCoder.description() == "UISegment" {
    ...
}

注: description()はクラス名をの形式<swift module name>.<actual class name>で返すため、文字列をaで分割し.て最後のトークンを取得します。
マシューQuiros 2015

4

ここでの回答の多くは、最新のSwift(執筆時点ではXcode 7.1.1)では機能しません。

情報を取得する現在の方法は、を作成しMirrorて問い合わせることです。クラス名は次のように簡単です。

let mirror = Mirror(reflecting: instanceToInspect)
let classname:String = mirror.description

オブジェクトに関する追加情報もから取得できますMirror。詳細については、http://swiftdoc.org/v2.1/type/Mirror/を参照してください。


stackoverflow.com/a/25345480/1187415およびstackoverflow.com/a/32087449/1187415の回答の何が問題になっていますか?どちらも、スウィフト2と非常によく動作するようです(持ってはいない他のものをチェックする。)
マーティンR

私はこれを一般的な解決策として気に入っていますが、「ViewControllerのミラー」(外部の「Mirror for」)を取得しています-待ってください。「。subjectType」を使用するとうまくいきます。
David H

3

ベータ5以降のlldbでは、次のコマンドでオブジェクトのクラスを確認できます。

fr v -d r shipDate

これは次のようなものを出力します:

(DBSalesOrderShipDate_DBSalesOrderShipDate_ *) shipDate = 0x7f859940

コマンドを展開すると、次のような意味になります。

Frame Variable (フレーム変数を出力) -d run_target(動的タイプを展開)

「フレーム変数」を使用して変数値を出力すると、コードが実行されないことが保証されます。


3

私は自分で開発したクラス(またはアクセスできるクラス)の解決策を見つけました。

次の計算プロパティをオブジェクトクラス定義内に配置します。

var className: String? {
    return __FILE__.lastPathComponent.stringByDeletingPathExtension
}

これで、オブジェクトのクラス名を次のように呼び出すだけです。

myObject.className

これは、名前を付けたいクラスとまったく同じ名前のファイル内でクラス定義が作成されている場合にのみ機能することに注意してください。

これは一般的なケースであるため、上記の回答はほとんどの場合にそれを行う必要があります。ただし、一部の特殊なケースでは、別のソリューションを理解する必要がある場合があります。


クラス(ファイル)自体の中にクラス名が必要な場合は、次の行を使用できます。

let className = __FILE__.lastPathComponent.stringByDeletingPathExtension

たぶん、この方法はある人々を助けるでしょう。


3

上記のKlassとKevin Ballardの回答とコメントに基づいて、私は次のようにします。

println(_stdlib_getDemangledTypeName(now).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(soon).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(soon?).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(soon!).componentsSeparatedByString(".").last!)

println(_stdlib_getDemangledTypeName(myvar0).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(myvar1).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(myvar2).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(myvar3).componentsSeparatedByString(".").last!)

印刷されます:

"NSDate"
"ImplicitlyUnwrappedOptional"
"Optional"
"NSDate"

"NSString"
"PureSwiftClass"
"Int"
"Double"

これがより良い答えだと思います。
maschall 2015

私はSwift 1.2で次のように使用する toString(self.dynamicType).componentsSeparatedByString(".").last!ことになりましたself
ジョー

3
let i: Int = 20


  func getTypeName(v: Any) -> String {
    let fullName = _stdlib_demangleName(_stdlib_getTypeName(i))
    if let range = fullName.rangeOfString(".") {
        return fullName.substringFromIndex(range.endIndex)
    }
    return fullName
}

println("Var type is \(getTypeName(i)) = \(i)")

3

Swiftバージョン4:

print("\(type(of: self)) ,\(#function)")
// within a function of a class

ありがとう@Joshua Dance


3

スウィフト4:

// "TypeName"
func stringType(of some: Any) -> String {
    let string = (some is Any.Type) ? String(describing: some) : String(describing: type(of: some))
    return string
}

// "ModuleName.TypeName"
func fullStringType(of some: Any) -> String {
    let string = (some is Any.Type) ? String(reflecting: some) : String(reflecting: type(of: some))
    return string
}

使用法:

print(stringType(of: SomeClass()))     // "SomeClass"
print(stringType(of: SomeClass.self))  // "SomeClass"
print(stringType(of: String()))        // "String"
print(fullStringType(of: String()))    // "Swift.String"

2

任意の値の型の型名を出力する一般的な方法はないようです。他の人が指摘したように、クラスインスタンスの場合は印刷できますvalue.classNameが、プリミティブ値の場合、実行時に型情報が失われたように見えます。

たとえば、入力する方法がないかのように見え、任意の値を1.something()取得しIntますsomething。(別の答えが示唆i.bridgeToObjectiveC().classNameするように、ヒントを与えるために使用できますが、実際にはタイプで__NSCFNumberなくi、Objective-C関数呼び出しの境界を越えたときに変換されるだけです。)

私は間違っていることが証明されて嬉しいですが、型チェックはすべてコンパイル時に行われ、C ++(RTTIが無効になっている)のように、型情報の多くは実行時に失われます。


Xcode6の遊び場で機能する私の例では、classNameを使用して変数「now」の「NSDate」を出力する例を挙げられますか?私が知る限り、classNameはSwiftオブジェクトで定義されていません。NSObjectのサブクラスのオブジェクトでも定義されています。
Matt Bridges、2014年

'className'はNSObjectの子孫のオブジェクトで使用できるようですが、iOS用ではなくMac用に開発している場合のみです。iOSには回避策がないようです。
Matt Bridges

1
ええ、ここでの本当の要点は、一般的なケースでは、型情報が実行時に迅速に失われることです。
ipmcc 2014年

ただし、REPLが値のタイプを出力できる方法に興味があります。
Matt Bridges 2014年

REPLはほぼ確実に解釈され、コンパイルされないため、簡単に説明できます
ipmcc

2

これは、オブジェクトまたはタイプの文字列を取得する方法であり、一貫性があり、オブジェクト定義が属するモジュールまたはネストされているモジュールを考慮に入れます。Swift4.xで動作します。

@inline(__always) func typeString(for _type: Any.Type) -> String {
    return String(reflecting: type(of: _type))
}

@inline(__always) func typeString(for object: Any) -> String {
    return String(reflecting: type(of: type(of: object)))
}

struct Lol {
    struct Kek {}
}

// if you run this in playground the results will be something like
typeString(for: Lol.self)    //    __lldb_expr_74.Lol.Type
typeString(for: Lol())       //    __lldb_expr_74.Lol.Type
typeString(for: Lol.Kek.self)//    __lldb_expr_74.Lol.Kek.Type
typeString(for: Lol.Kek())   //    __lldb_expr_74.Lol.Kek.Type

2

取得するには、オブジェクトのタイプまたはオブジェクトのクラススウィフトを、あなたが使用する必要がなければなりません(:yourObjectの)タイプを

type(of:yourObject)


1

正確には何をしているのかではありませんが、次のように変数の型をSwiftの型と照合することもできます。

let object: AnyObject = 1

if object is Int {
}
else if object is String {
}

例えば。


1

Xcode 7.3.1、Swift 2.2:

String(instanceToPrint.self).componentsSeparatedByString(".").last

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.