iOSDCで参考になった技術を深掘りする
今回は時間の関係で下の英語の記事の一部を翻訳したものを上げます。翻訳の許可を頂いてます。
Dynamic Member Lookupの箇所です。
理由はあとがきに書いていますが、@dynamicMemberLookupの登場がSwiftコミュニティとPythonコミュニティに大きなインパクトを与える可能性が大きいことです。
チュートリアル用のサンプルファイルはこちらのリンクからダウンロードできます。
Understanding Dynamic Member Lookup
Swift 4.2の変更に追いついているのであれば、Dynamic Member Lookupについて聞いたことがあります。 そうでない場合は、ここで概念を学ぶだけでなく様々なことを学ぶでしょう。
チュートリアルのこの部分では、JSONディクショナリから値にアクセスするためにドット表記を使用できるようにする、実際のJSON DSL(Domain Specification Language)を作成する方法の例を見て、SwiftのDynamic Member Lookupのパワーが分かるでしょう。
Dynamic Member Lookupを使用すると、コーダーがコンパイル時に存在しないプロパティに対してドットシンタックスで使用できるようになります。要するに、実行時にメンバーが存在し、そのプロセスで読みやすいコードを取得することを信じてコーディングしています。
この機能の提案やSwiftコミュニティでの関連する会話で述べたように、この機能はPythonのような他の言語との相互運用性をサポートし、データベース実装者やCoreImageなどの文字列型APIに関する定型的なラッパーを作成します。
Introducing @dynamicMemberLookup
DogCatcherページを開き、コードを確認します。 playgroundでは、DogはDogがDirectionで走っている方法を表します。
dynamicMemberLookupの力で、directionOfMovementとmovingは、それらのプロパティが明示的に存在しなくてもアクセスできます。 犬をダイナミックになる時です。
Adding dynamicMemberLookup to the Dog
この動的パワーを有効にする方法は、type属性@dynamicMemberLookupの使用することです。
Directionを返すsubscriptメソッドを追加する上で下記のコードを追加します。
subscript(dynamicMember member: String) -> Direction {
if member == "moving" || member == "directionOfMovement" {
// Here's where you would call the motion detection library
// that's in another programming language such as Python
return randomDirection()
}
return .motionless
}
☆マークされた行のコメントを外して、dynamicMemberLookupをDogに追加します。☆この行の上にDogのコメントを外します。
directionOfMovementまたはmovingというプロパティにアクセスできるようになりました。後の行に次の行を追加して試してみましょう☆ここでdynamicDogにdynamicMemberLookup機能を使用してください:
let directionOfMove: Dog.Direction = dynamicDog.directionOfMovement
print("Dog's direction of movement is \(directionOfMove).")
let movingDirection: Dog.Direction = dynamicDog.moving
print("Dog is moving \(movingDirection).")
playgroundをRunしましょう。 値が残っていることもあれば正しくないこともありますが、最初に表示される2行は次のようになります。
Dog's direction of movement is left.
Dog is moving left.
Overloading subscript(dynamicMember:)
Swiftは、異なる戻り型の添字宣言のオーバーロードをサポートしています。Intを右下に返す添え字を追加することでこれを試してみましょう
☆Intを返す添字メソッドを追加する:
subscript(dynamicMember member: String) -> Int {
if member == "speed" {
// Here's where you would call the motion detection library
// that's in another programming language such as Python.
return 12
}
return 0
}
これでspeedというプロパティにアクセスできます。 あなたが以前に追加した以下のmovingDirectionを追加して、勝利を勝ち取ろう:
let speed: Int = dynamicDog.speed
print("Dog's speed is \(speed).")
playgroundをRunしましょう。こんな風に出力されると思います。
Dog's speed is 12.
かなりいいですね?@dynamicMemberLookupは、Pythonなどの他のプログラミング言語にアクセスする必要がある場合でも、コードを見栄えの良いものにする強力な機能です。
Compiler and Code Completion Gone to the Dogs
この動的ランタイム機能と引き換えに、subscript(dynamicMember :)機能に依存するプロパティのコンパイル時チェックのメリットはありません。また、Xcodeのコード補完機能もあなたを助けません。しかし、良いニュースは、プロのiOS開発者が書くよりも多くのコードを読むことです。
Dynamic Member Lookupが提供するシンタックスシュガーは、ただ捨てるだけのものではありません。これはSwiftの特定のユースケースと言語の相互運用性を保証し、楽しく素晴らしい機能です。
Friendly Dog Catcher
Dynamic Member Lookupのオリジナルの提案は、特にPythonでの言語相互運用性に対処しました。しかし、それが有用な唯一の状況ではありません。
純粋なSwiftユースケースを示すために、DogCatcher.xcplaygroundpageにあるJSONDogCatcherコードを操作します。これは、String、Int、およびJSON辞書を処理するために設計されたいくつかのプロパティを持つシンプルな構造体です。このような構造体を使用すると、JSONDogCatcherを作成し、最終的に特定のString値またはInt値を検索することができます。
Traditional Subscript Method
このような構造体を使用してJSONディクショナリに掘り下げる伝統的な方法は、添字法を使用することです。playgroundにはすでに従来の添字実装が含まれています。 添字メソッドを使用してString値またはInt値にアクセスすると、通常は次のようになり、またplaygroundにも表示されます。
let json: [String: Any] = ["name": "Rover", "speed": 12,
"owner": ["name": "Ms. Simpson", "age": 36]]
let catcher = JSONDogCatcher.init(dictionary: json)
let messyName: String = catcher["owner"]?["name"]?.value() ?? ""
print("Owner's name extracted in a less readable way is \(messyName).")
角かっこ、引用符、疑問符を見なければなりませんが、これは機能します。
playgroundをRunしましょう。 次のように表示されます。
Owner's name extracted in a less readable way is Ms. Simpson.
それはうまく動作しますが、ドットシンタックスを使用するだけで目がより簡単になります。Dynamic Member Lookupを使用すると、複数レベルのJSONデータ構造を掘り下げることができます。
Adding dynamicMemberLookup to the Dog Catcher
Dogのように、JSONDogCatcher構造体にdynamicMemberLookup属性を追加します。
☆JSONDogCatcherを返す添え字(dynamicMember :)メソッドをここに追加してください。
subscript(dynamicMember member: String) -> JSONDogCatcher? {
return self[member]
}
添字(dynamicMember :)メソッドは既存の添え字メソッドを呼び出しますが、角かっことStringキーを使用する定型コードを削除します。SONDogCatcherの上にこの行のコメントを外してください:
@dynamicMemberLookup
struct JSONDogCatcher {
それで、ドット表記法を使って犬のスピードとオーナーの名前を得ることができます。☆キャッチャーでオーナーの名前とスピードを取得するには、ドット表記を使用してください。
let ownerName: String = catcher.owner?.name?.value() ?? ""
print("Owner's name is \(ownerName).")
let dogSpeed: Int = catcher.speed?.value() ?? 0
print("Dog's speed is \(dogSpeed).")
playgroundをRunしましょう。 コンソールでスピードとオーナーの名前を確認してください:
Owner's name is Ms. Simpson.
Dog's speed is 12.
あなたはオーナーの名前を持っているので、犬のキャッチャーはオーナーに連絡して、彼女の犬が見つかったことを知らせることができます!
なんて幸せな結末なんでしょう! 犬とその所有者が再び一緒になり、コードがよりきれいに見えます。ダイナミックなSwiftの力によって、このダイナミックな犬は裏庭のバニーを追うことに戻ることができます。
あとがき
拙い翻訳で申し訳ございません。
一部、何を言っているのか分からない英語がありましたので適当に日本語っぽい文章にしてみました。(特に☆マークが付いている箇所)
簡単に何がすごいのかと言うと**@dynamicMemberLookupの登場によってSwiftからPythonコードやライブラリをインポートして使えるようになっただけでなくPythonコードをSwiftぽくドットシンタックスでプロパティにアクセスできるようになった**と言うことです。
もちろん、Python連携ができるようになることもインパクトが大きいですが、PythonをSwiftで操作するとtypoしやすくなるのでそれをSwiftぽく書けるようになるのは作業効率がとても良くなります。
あとの詳しいことは @koher さんのiOSDC2018のこのLTのプレゼン資料を見ていただけたらわかりやすいと思いました。
(勝手に引用してしまってすみません。)
iOSDC2018の中で個人的に一番感動したのがこのLTでしたので。
で、この@dynamicMemberLookup ともう一つ注目したいのが、
LTで紹介されていたSwift for TensorFlowの内容でした。
このライブラリでTensorFlowをSwiftで操作できると言うこと。
コントリビューターにもちろんChris Lattnerの名前が入っているのが印象的ですね。
これがうまく言えば、SwiftがPythonをうまく吸収することができて一気に世の中に浸透するんだとか。
早くSwiftが世界のTop1になってほしい自分は早くこのプロジェクトが成功してほしいと思ってます。
ちなみにこのdynamicMemberLookupってこの記事で最初に取り上げてます。