Swiftはリフレクションをサポートしていますか?


113

Swiftはリフレクションをサポートしていますか?例えばのようなものがあるvalueForKeyPath:setValue:forKeyPath:スウィフトのオブジェクトのためには?

実際にはobj.class、Objective-Cのような動的な型システムもありますか?


1
Swiftでリフレクション用のヘルパークラスを作成しました。:あなたはでそれを見つけることができますgithub.com/evermeer/EVReflection
エドウィン・フェルメール

2
Swift 2.0内のReflectは削除されました。これが私が属性と値を列挙する方法ですリンク
mohacs

回答:


85

いくつかのリフレクションのサポートが始まったようです:

class Fruit {
    var name="Apple"
}

reflect(Fruit()).count         // 1
reflect(Fruit())[0].0          // "name"
reflect(Fruit())[0].1.summary  // "Apple"

mchambers gistから、ここ:https ://gist.github.com/mchambers/fb9da554898dae3e54f2


5
まあ、私はこれを本当の反射とは考えません。一つには、それは読み取り専用です。Xcodeでデバッグを有効にするためのハックにすぎないようです。プロトコルはMirror実際に単語をIDE数回引用します。
Sulthan

7
また、プロパティに対してのみ機能します。メソッドリフレクションはありません。
Sulthan

11
要点のチェックインの作成者。これをWWDCのSwiftラボで書いたので、残りの部分は共有します。誰もが理解しているように、私が話をしたエンジニアは、playgroundをサポートするためのReflect()関数が存在することを確認しました。しかし、あなたはそれでまだいくつかの楽しみを持つことができます:)ここで私はそれを使用して小さなモデルのシリアライザをハッキングしました。それをプレイグラウンドに貼り付けて楽しんでください:gist.github.com/mchambers/67640d9c3e2bcffbb1e2
Marc Chambers

1
答えがStackoverflow.com/a/25345461/292145でどのように_stdlib_getTypeName役立つかを確認してください。
Klaas 2014

1
基本クラスとオプション(型ではない)のリフレクションを行い、ディクショナリとの間のNSCodingおよび解析をサポートするクラスは次のとおり
Edwin Vermeer

44

クラスがを拡張する場合、NSObjectObjective-Cの内省とダイナミズムはすべて機能します。これも:

  • クラスにそのメソッドとプロパティについて質問し、メソッドを呼び出したり、プロパティを設定したりする機能。
  • メソッド実装を交換する機能。(すべてのインスタンスに機能を追加します)。
  • その場で新しいサブクラスを生成して割り当てる機能。(特定のインスタンスに機能を追加します)

この機能の1つの欠点は、Swiftのオプションの値タイプがサポートされていることです。たとえば、Intプロパティは列挙および変更できますが、Int?プロパティはできません。オプションの型は、reflect / MirrorTypeを使用して部分的に列挙できますが、変更はできません。

クラスが拡張しない場合、NSObject新しい非常に限定された(そして進行中の)リフレクションのみが機能し(reflect / MirrorTypeを参照)、クラスとプロパティについてインスタンスに質問する機能が制限されますが、上記の追加機能はありません。

NSObjectを拡張しない場合、または '@objc'ディレクティブを使用する場合、Swiftはデフォルトで静的およびvtableベースのディスパッチを行います。これはより高速ですが、仮想マシンがない場合、ランタイムメソッドのインターセプトは許可されません。このインターセプトはCocoaの基本的な部分であり、次のタイプの機能に必要です。

  • ココアのエレガントな物件オブザーバー。(プロパティオブザーバーは、Swift言語に組み込まれています)。
  • ロギング、トランザクション管理(つまり、アスペクト指向プログラミング)などの分野横断的な懸念を非侵襲的に適用する。
  • プロキシ、メッセージ転送など

したがって、Swiftを使用して実装されたCocoa / CocoaTouchアプリケーションに留めることをお勧めします。

  • NSObjectから拡張します。Xcodeの新しいクラスダイアログは、この方向に進みます。
  • 動的ディスパッチのオーバーヘッドがパフォーマンスの問題につながる場合、静的ディスパッチを使用できます。たとえば、非常に小さいボディを持つメソッドを呼び出すようなタイトなループで使用できます。

概要:

  • SwiftはC ++のように動作でき、静的/ vtableディスパッチが高速で、リフレクションが制限されています。これにより、低レベルまたはパフォーマンス集約型のアプリケーションに適していますが、C ++に関連する複雑さ、学習曲線、またはエラーのリスクはありません。
  • Swiftはコンパイルされた言語ですが、メソッド呼び出しのメッセージングスタイルは、Objective-Cのように、RubyやPythonなどの現代の言語で見られる内省とダイナミズムを追加しますが、Objective-Cのレガシー構文はありません。

参照データ:メソッド呼び出しの実行オーバーヘッド:

  • 静的:<1.1ns
  • vtable:〜1.1ns
  • ダイナミック:〜4.9ns

(実際のパフォーマンスはハードウェアに依存しますが、比率は同じままです)。

また、dynamic属性を使用すると、メソッドで動的ディスパッチを使用するようにSwiftに明示的に指示できるため、インターセプトがサポートされます。

public dynamic func foobar() -> AnyObject {
}

2
Objective-Cテクニックを使用しても、オプションのSwiftタイプでは機能しないようです。トリックを見逃していない限り、この制限を回答で指摘することをお勧めします。
ホイットニーランド2014年

8

ドキュメントは動的型システムについて、主に

Type そして dynamicType

メタタイプタイプ(言語リファレンス)を参照してください。

例:

var clazz = TestObject.self
var instance: TestObject = clazz()

var type = instance.dynamicType

println("Type: \(type)") //Unfortunately this prints only "Type: Metatype"

TestObject拡張すると仮定しますNSObject

var clazz: NSObject.Type = TestObject.self
var instance : NSObject = clazz()

if let testObject = instance as? TestObject {
    println("yes!") //prints "yes!"
}

現在、リフレクションは実装されていません。

編集:私は明らかに間違っていました、stevexの答えを見てください。プロパティの組み込みには、おそらくIDEがオブジェクトの内容を検査できるようにするために、いくつかの単純な読み取り専用リフレクションがあります。


6

現時点では、SwiftリフレクションAPIはAppleにとって高い優先度ではないようです。しかし、@ stevexの回答の他に、標準ライブラリに役立つ別の関数があります。

ベータ6以降_stdlib_getTypeName、変数のマングル型名が取得されます。これを空の遊び場に貼り付けます。

import Foundation

class PureSwiftClass {
}

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

println( "TypeName0 = \(_stdlib_getTypeName(myvar0))")
println( "TypeName1 = \(_stdlib_getTypeName(myvar1))")
println( "TypeName2 = \(_stdlib_getTypeName(myvar2))")
println( "TypeName3 = \(_stdlib_getTypeName(myvar3))")

出力は次のとおりです。

TypeName0 = NSString
TypeName1 = _TtC13__lldb_expr_014PureSwiftClass
TypeName2 = _TtSi
TypeName3 = _TtSS

Ewan Swickのブログエントリは、これらの文字列を解読するのに役立ちます。

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

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


@aleclarsonはい、それも非常に便利です。
Klaas

1
それらのプライベートAPIではないですか?使用されている場合、アップルはアプリを承認しますか?
Eduardo Costa

@EduardoCostaはい、確かに。彼らはプライベートです。デバッグビルドにのみ使用します。
Klaas 2014

Ewan Swickのブログ記事への更新されたリンクは次のとおり
2014/06/08

5

代わりにtoString()の使用を検討してください。これはパブリックであり、_stdlib_getTypeName()まったく同じように機能しますがAnyClassでも機能する点が異なります。

class MyClass {}

toString(MyClass.self) // evaluates to "__lldb_expr_49.MyClass"

1

いいえreflectスウィフト5におけるキーワードは、今あなたが使用することはできません

struct Person {
    var name="name"
    var age = 15
}

var me = Person()
var mirror = Mirror(reflecting: me)

for case let (label?, value) in mirror.children {
    print (label, value)
}

なぜこれは賛成されないのですか?これは便利です。json逆シリアル化に適用します
javadba
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.