Swiftで変数の実行時型を表示する方法はありますか?例えば:
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!
型であることを示す方法を探しています。
2016年9月に更新
Swift 3.0:type(of:)
を使ってください。 type(of: someThing)
(dynamicType
キーワードが削除されたため)
2015年10月に更新 :
以下の例を新しいSwift 2.0の構文に更新しました(例:println
はprint
に置き換えられました、toString()
は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
型を表します。
編集: 新しいtoString
関数 がSwift 1.2(Xcode 6.3)で導入されました 。
.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.self
とyourObject.dynamicType
を呼び出してみてください。
これはあなたが探しているものですか?
println("\(object_getClassName(now))");
"__NSDate"を印刷します
_ update _ :これはBeta05の時点では動作しなくなったようです。
スイフト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>"
私の現在の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.
Swift 1.2を使ったXcode 6.3では、型の値を完全にデマングルされた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"
className
(String
を返す)を介してクラスにアクセスすることはできます。
クラスを取得するには、実際にはいくつかの方法があります。例えば、classForArchiver
、classForCoder
、classForKeyedArchiver
(すべてAnyClass!
を返す)などです。
プリミティブの型を取得することはできません(プリミティブはnot aクラスです)。
例:
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
オブジェクトに関する情報を取得するには、reflectを使用できます。
オブジェクトクラスの名前の例:
var classname = reflect(現在).summary
私は運が良かった:
let className = NSStringFromClass(obj.dynamicType)
Xcode 8 Swift 3.0の使用タイプ(of :)
let className = "\(type(of: instance))"
let type : Type = MyClass.self //Determines Type from Class
let type : Type = type(of:self) //Determines Type from self
let string : String = "\(type)" //String
Swift 3.0では、dynamicType
キーワードが削除されたため、type(of:)
を使用できます。
Swift 5
Swift 3の最新リリースでは、String
イニシャライザーを通じて型名のきれいな説明を取得できます。たとえば、print(String(describing: type(of: object)))
など。 object
インスタンス変数にすることができます配列、辞書、Int
、NSDate
、カスタムクラスのインスタンスなど
私の完全な答えは次のとおりです。 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()
出力は次のとおりです。
トップアンサーには、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'
私はここで他の答えのいくつかを試してみましたが、ミラージュは根底にあるオブジェクトが何であるかについて非常にあるようです。
しかし、次のようにして、オブジェクトの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を表示します。
私はうまくいけば他の人のために働くかもしれないこの解決策を見つけました。値にアクセスするためのクラスメソッドを作成しました。これはNSObjectサブクラスでのみ機能することに注意してください。しかし、少なくとも清潔できちんとした解決策です。
class var className: String!{
let classString : String = NSStringFromClass(self.classForCoder())
return classString.componentsSeparatedByString(".").last;
}
Cocoa(CocoaTouchではなく)を使用するときは、NSObjectのサブクラスであるオブジェクトにclassName
プロパティを使用できます。
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を通じて可能になるでしょう。
_ edit _ :dump(object)
がうまくいくようです。
Swift 1.2を搭載した最新のXCode 6.3では、これが私が見つけた唯一の方法です。
if view.classForCoder.description() == "UISegment" {
...
}
上記の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"
私は自己開発クラスの解決策(またはあなたがアクセスできるものなど)を見つけました。
次の計算プロパティをオブジェクトクラス定義内に配置します。
var className: String? {
return __FILE__.lastPathComponent.stringByDeletingPathExtension
}
これで、オブジェクトのクラス名を次のようにして呼び出すことができます。
myObject.className
これは正確にあなたのクラス定義があなたが望む名前のクラスのような正確にという名前のファイル内で作られることに注意してください。
これは 一般的に case 上記の答えはほとんどの場合それを行うべきですです。しかし、 some の特別な場合には、別の解決策を考え出す必要があるかもしれません。
クラス名クラス(ファイル)自体の中が必要な場合は、単に次の行を使用できます。
let className = __FILE__.lastPathComponent.stringByDeletingPathExtension
たぶん、この方法はそこの何人かの人々を助けます。
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)")
ベータ5以降のlldbでは、次のコマンドでオブジェクトのクラスを見ることができます。
fr v -d r shipDate
これは次のように出力されます。
(DBSalesOrderShipDate_DBSalesOrderShipDate_ *) shipDate = 0x7f859940
展開されたコマンドは次のようなものを意味します。
Frame Variable
(フレーム変数を印刷する)-d run_target
(動的型を展開する)
「フレーム変数」を使用して変数値を出力すると、コードが実行されないことが保証されます。
ここでの回答の多くは最新のSwift(執筆時点ではXcode 7.1.1)では機能しません。
情報を得るための現在の方法はMirror
を作成しそれを調べることです。クラス名の場合は、次のように単純です。
let mirror = Mirror(reflecting: instanceToInspect)
let classname:String = mirror.description
オブジェクトに関する追加情報もMirror
から取得できます。詳細は http://swiftdoc.org/v2.1/type/mirror/ を参照してください。
Swift version 4:
print("\(type(of: self)) ,\(#function)")
// within a function of a class
ありがとうジョシュアダンス
任意の値の型の型名を表示する一般的な方法はないようです。他の人が指摘したように、 class インスタンスではvalue.className
を印刷できますが、プリミティブな値では実行時に型情報が消えたように見えます。
たとえば、1.something()
と入力してInt
の任意の値に対してsomething
を取得する方法がないかのように見えます。 (別の回答として、i.bridgeToObjectiveC().className
を使用してヒントを得ることもできますが、__NSCFNumber
は not 実際にはi
の型です。Objective-C関数の境界を越えたときに変換されるものですコール。)
私は間違っていることを証明できればうれしいですが、型チェックはすべてコンパイル時に行われ、C++(RTTIを無効にした状態)のように実行時に消えてしまいます。
これは、 object または Type の型文字列を取得する方法で、これは 一定の であり、オブジェクト定義が属する module のどちらに属するかを考慮します。 Swift 4.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
// "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"
厳密にはあなたがしていることではありませんが、Swiftの型に対して変数の型をチェックすることもできます。
let object: AnyObject = 1
if object is Int {
}
else if object is String {
}
例えば。
Xcode 7.3.1、Swift 2.2:
String(instanceToPrint.self).componentsSeparatedByString(".").last
Swift 3.0、Xcode 8
次のコードで、インスタンスにそのクラスを問い合わせることができます。また、2つのインスタンスを比較して、同じクラスにすることもできます。
// CREATE pure Swift class
class MySwiftClass {
var someString : String = "default"
var someInt : Int = 5
}
// CREATE instances
let firstInstance = MySwiftClass()
let secondInstance = MySwiftClass()
secondInstance.someString = "Donald"
secondInstance.someInt = 24
// INSPECT instances
if type(of: firstInstance) === MySwiftClass.self {
print("SUCCESS with ===")
} else {
print("PROBLEM with ===")
}
if type(of: firstInstance) == MySwiftClass.self {
print("SUCCESS with ==")
} else {
print("PROBLEM with ==")
}
// COMPARE CLASS OF TWO INSTANCES
if type(of: firstInstance) === type(of: secondInstance) {
print("instances have equal class")
} else {
print("instances have NOT equal class")
}
タイプのオブジェクト または オブジェクトのクラス をSwiftに取得するには、 タイプ(of:yourObject)を使用する必要があります
タイプ(of:yourObject)
以下のコードスニペットを見て、あなたが以下のような何かを探しているかどうか私に知らせてください。
var now = NSDate()
var soon = now.addingTimeInterval(5.0)
var nowDataType = Mirror(reflecting: now)
print("Now is of type: \(nowDataType.subjectType)")
var soonDataType = Mirror(reflecting: soon)
print("Soon is of type: \(soonDataType.subjectType)")
これは、オブジェクトがクラスの型かどうかを調べるときにも便利です。
if someObject is SomeClass {
//someObject is a type of SomeClass
}
String(describing: type(of: self))
から返されるクラス名に影響を与えるもう一つの重要な側面は Access Control です。
Swift 3.1.1 、 Xcode 8.3.3 (2017年7月)に基づいて、次の例を検討してください。
func printClassNames() {
let className1 = SystemCall<String>().getClassName()
print(className1) // prints: "SystemCall<String>"
let className2 = DemoSystemCall().getClassName()
print(className2) // prints: "DemoSystemCall"
// private class example
let className3 = PrivateDemoSystemCall().getClassName()
print(className3) // prints: "(PrivateDemoSystemCall in _0FC31E1D2F85930208C245DE32035247)"
// fileprivate class example
let className4 = FileprivateDemoSystemCall().getClassName()
print(className4) // prints: "(FileprivateDemoSystemCall in _0FC31E1D2F85930208C245DE32035247)"
}
class SystemCall<T> {
func getClassName() -> String {
return String(describing: type(of: self))
}
}
class DemoSystemCall: SystemCall<String> { }
private class PrivateDemoSystemCall: SystemCall<String> { }
fileprivate class FileprivateDemoSystemCall: SystemCall<String> { }
ご覧のとおり、この例のすべてのクラスはそれぞれのString
表現に影響を与えるさまざまなレベルのアクセス制御を持っています。クラスがprivate
またはfileprivate
アクセス制御レベルを持つ場合、Swiftは問題のクラスの "ネスト"クラスに関連するある種の識別子を追加するようです。
PrivateDemoSystemCall
とFileprivateDemoSystemCall
の両方の結果は、両方とも同じ親クラスにネストされているため、同じ識別子が追加されます。
私はそれを取り除くための方法をまだ見つけていません。
たった2セントです。