平日に戻ったら復習の機会もなくなるのでできるだけスライドとかで復習していきます。ここに書いた以外にも素晴らしいセッションがたくさんありましたが、会場で理解が追いつかなかったもの、あまりちゃんと聞けなかったものを中心に。
Keypath入門 - Introduction to Swift Keypaths
SwiftのKeyPathを使って型の抽象化を行う話。例として、以下のような全然違う要素を持つStructを抽象化するのはProtocolだとできないけど、KeyPathを使えばできるよ、と。
こういうStructがあるとして、
structUser { varusername:String } varplayer= User(username:"マリオ")
で、Swiftのキーパスではこんな感じでUser
の持つusername
にアクセスできる。
player[keyPath: \User.username] ="リンク"
(この書式、全く知らなかった)
こんな感じで変数に格納することもできる。
letnameKeyPath= \User.username player[keyPath:nameKeyPath] ="ルイージ"
で、キーパスには色々種類があるという話と、
- KeyPath<Root, Value>
- WritableKeyPath<Root, Value>
- ReferenceWritableKeyPath<Root, Value>
- PartialKeyPath
- AnyKeyPath
合成できるという話があって、
これらの性質を使って、冒頭に挙げたSettingsを表す要素の全然違うStructをどう抽象化するか、という具体例について説明される。
あとKeyPathはHashableなのでDictionaryのキーにも使えますよ、とか。
Swiftにおける音の成形
スライドはGitHubにある。
このセッションは音の基礎から始まって、で、iOSではどうやるの?というところでCore Audioは難しいからAudioKit使おう、という流れ。
音声処理は興味がある。が、あんまり「音楽」の文脈では興味がなくて、どっちかというと「現実世界をセンシングする」という文脈で興味がある。このセッションは音楽寄りの話なのでそういう意味では僕の興味にストライクではなかったが、AudioKitがディレイやリバーブのような基本的な処理だけじゃなくてAKMoogLadderみたいなかなりアプリケーションよりのところまで含んでいるというのは知見だった。
試しにAudioKitのプロジェクトでvoiceでクラス群をフィルタしてみると、SamplerVoiceとかSynthVoiceとか興味深いクラスがあるし、MIDI系の実装も充実している。あとAudioKitのリポジトリはAudioKitというアカウントにあって、
サンプルとか、音をパーティクルでビジュアライズするプロジェクトもある。
Metalを使用。あとでちゃんとコードを読んでみようと思う。
(iPhoneでも普通に動いた)
PixarのようなグラフィックをSwiftで実現する
レイトレーシングの話。iOS 12でMetalに追加されたレイトレーシングの話かと思いきや、
シンプルなレイトレーサーをSwiftで自前実装する、という話だった。めちゃくちゃいい。自分で実装するというのは理解度が全然違う。
コードはGitHubにある。
"Pete Shirley"という人の書籍を参考に書いたコードらしい。
Much of the code is derived from Pete Shirley's Ray Tracing Minibooks, with a few added extras.
で、このリポジトリ、Swiftのファイルが2つとビルドスクリプトしか入ってない。Xcodeプロジェクトはなく、コマンドからビルドして各フレームの画像をppmで出力し、それらをffmpegに食わせてmp4として吐き出すというもののようだ。
中身を見ると、Metalを使ってないどころか、SceneKitもCore ImageもCore Graphicsも使ってない。Foundationだけ。
#tryswiftconfで出てきたSwiftでのレイトレーシング実装、MetalやSceneKitどころか他のグラフィックス系APIも使ってなくて、Foundationしか使ってない。2つのSwiftファイルがあるだけ。これだけであんな表現ができるのか。。 https://t.co/X8XK5LJW1a
— Shuichi Tsutsumi (@shu223) March 23, 2019
(ということをツイートしたら、レイトレーシングという(iOS界隈では)ニッチな話題にもかかわらず結構な反響があった)
次のようなアルゴリズムらしい。
- Line sphere intersection
- Path tracing
- Lamberian scattering
- Fresnel equations
- Schlick approximation
- Perlin noise
- Rodrigues rotation formula
これはたぶんコードを読むだけでは何やってるかわからないやつだ。。まぁそれぞれのアルゴリズムの日本語名を調べて、何をやってるのか(中身の詳細はブラックボックスでもいいので)理解する、ぐらいのことはやりたい。
SwiftSyntax で便利を実現する基礎
SwiftSyntaxというSwiftの公式ライブラリがあって、それを使って構文解析したり、コードの一部を書き換えたり(修正コードを生成)する方法の紹介。
めっちゃわかりやすいけど、会場ではボーッとしてて(スライドが日本語だったのでそこが気になって回想モードに入ってしまった)、『SwiftSyntaxは公式ライブラリである』というところを聞き逃してしまい、構文解析がどのように行われるかを解説しているのか、Swiftのコンパイラ実装の一部を取り出してツールとして利用するような話をしているのか、みたいに理解の迷子になってしまった。プレゼンを聞くときは冒頭は絶対に聞き逃してはいけない。。
Swift type metadata
SwiftのType metadataを通じてSwiftのランタイムを理解しよう、というセッション。
letmetatype:Int.Type= Int.self
このInt.Type
は「メタタイプ(Metatype)」と呼ばれる型で、クラスや構造体、列挙型、プロトコル等、型を表すための型。{型名}.self
でこのメタタイプを型自体から取得できる。
で、このセッションの主役である"type metadata"は、Swiftランタイムにおいて型の情報を表すデータで、Metatypeはtype metadataへのポインタである、とのこと。
これを用いて、Method swizzlingも可能になる。
classAnimal { funcbar() { print("bar") } funcfoo() { print("foo") } } structClassMetadata { ...// VTablevarbarRef:FunctionRefvarfooRef:FunctionRef } letmetadata= unsafeBitCast( Animal.self, to:UnsafeMutablePointer<ClassMetadata>.self ) letbar= withUnsafeMutablePointer(to:&metadata.pointee.barRef) { $0 } letfoo= withUnsafeMutablePointer(to:&metadata.pointee.fooRef) { $0 } bar.pointee = foo.pointee letanimal= Animal() animal.bar() // foo
これを利用したOSSがStubKitで、
Decodableに準拠している任意のクラスや構造体を1行で初期化できるようにしてくれる、というものらしい。
import StubKit // Codable structstructUser:Codable { letid:Intletname:Stringletsex:Sex } letstubUser= try Stub.make(User.self) // User(id: 1234, name: "This is Stub String", sex: .female)
便利そう。
通常の開発ではあまり見ることのない言語の「内部」を読み解き、さらに実用面での使いどころを考え、OSSにまで落とし込む(しかもかなり普遍性がある)という一連の所業は見習いたい。
ポートレートモードを自作しよう / Making Portrait mode yourself
深度情報が付属しない2D画像、しかも現実世界の写真だけじゃなくてたとえばマンガやアニメの画像も背景をぼかしたりしたい、という試み。
深度推定の機械学習モデル使うのかなと思ったが、違った。それだと期待した性能が出ない(機械学習なので、学習させたシーンの背景しか分離できない)ので、"GrabCut"なるアルゴリズムを採用したとのこと。
LTなのでアルゴリズムの詳細説明はなくサッと次のスライドに行ってしまったので、帰ってググってみたところ、2004年の論文で提案されたアルゴリズムのようだった。
try! Swiftの当該セッションの実装コードを見ると、OpenCVにそのものズバリな関数が用意されていて、それを使っているようだった。
cv::grabCut(sourceMat, maskMat, rectangle, bgModel, fgModel, iterationCount, cv::GC_INIT_WITH_RECT);
これはいいことを知った。デュアルカメラやTrueDepthがハイエンドiPhoneに限定されたスペックである以上、iOSが13になろうと14になろうとデプス取得手段がないデバイスで撮影された画像への対処は必要で、こういう手段もある、というのは知れてよかった。
OpenCVの公式サイトに色々とドキュメントがある。
画像処理界隈ではよく知られたアルゴリズムのようで、"grabcut opencv"でググると日本語情報もたくさん出てくる。
つづく
復習したいセッションのリストはまだまだあるので、つづきます。