ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
Combineの紹介
Combineは、時間の経過に沿って値を処理するための統一された宣言型フレームワークです。このセッションでは、ネットワーキング、キー値の監視、通知やコールバックといった非同期コードがCombineによってどのように合理化されるかについて説明します。
リソース
関連ビデオ
WWDC19
-
ダウンロード
(音楽)
(拍手) どうも ありがとう Foundationチーム マネージャーのパーカーです 今日は新しいフレームワークを 紹介します Combineです 非同期処理の話です
魔法学校へ登録するための アプリケーションを作っています 要件は非常に簡単です まず ネットワークリクエストで ユーザ名を確認します アプリケーション内で確認できる パスワードもです 応答の早いユーザインターフェイスも 不可欠です
動作を見てみましょう まずユーザ名を打ち込みます 魔法使いらしく “マーリン”としましょう すでに非同期処理が起こっています Target/Actionで ユーザーの入力通知を待ちます ユーザーが入力を終えるのを 待つためにTimerを使い Serverの過負荷を避けました 非同期処理の状況を把握するため KVOも使いました ここで UIをアップデートする 必要があるとの応答があり 新しいユーザ名を選び パスワードを入れます こんなパスワードはダメですよ 更に非同期処理がされました URLSessionへの応答を待ち 同期チェックの結果と マージさせました 処理がすべて完了した時点で KVCを使い 再びUIをアップデートします
Cocoa SDKには 非同期インターフェイスが多々あります NotificationCenterや Ad Hocコールバックなどです これらはクロージャなどのAPIです すべて重要で 用途が違いますが これらの併用は 難しいこともあります Combineではこれらを使いながら 共通項を見つけます 経時的に値を処理する 統一的かつ宣言的なAPIです
Swiftを使いますから― ジェネリクスなどの機能も利用可能 入力するひな型が減らせます また 非同期処理の アルゴリズムを一度書いて 他の非同期インターフェイスに 適用できます
Combineはタイプセーフで コンパイル時にエラーを見つけられます Combineの目的は “組み合わせること”です シンプルで簡単なコンセプトですが 単なる複合より すごいことができるのです また リクエスト駆動型なので メモリやパフォーマンスを より細かく管理できるのです 主題は パブリッシャー サブスクライバーとオペレーターの3つ ますはパブリッシャーについてです
Combine APIの宣言的な部分です 値やエラーがどう出たかを 表示しますが それらの発生には関与しません つまり値型なので Swiftでは構造体を使います パブリッシャーはサブスクライバーの 登録を可能にし 値を受け取り続けることができます プロトコルです パブリッシャーに 関連型が2種類あり Outputが出てきた値で Failureはエラーです エラーが発生しないのであれば Neverと設定できます パブリッシャーの主要機能は サブスクライブです GenericConstraintから分かるように パブリッシャーとサブスクライバー間で インプットなどを合わせます
NotificationCenterの 新しいパブリッシャーの例です ご覧のように 構造体で OutputがNotification FailureはNeverです centerとnameと objectで初期化されます NotificationCenterをご存知なら 見慣れた型でしょう NotificationCenterは そのまま使えます
サブスクライバーは パブリッシャーと対になるものです 値を受け取り 完了報告を受けます 値の受信により 状態が変化するので クラスを持つSwiftの参照型を 使います プロトコルです こちらの関連型も InputとFailureですね エラーを受け付けないのであれば Neverとします 主な機能は3つ 1つはサブスクリプションの受信 パブリッシャーから受け取った データの処理履歴です インプットも受け取れます パブリッシャーが有限である場合 FinishedかFailureの 完了報告を受信します
例を見てみましょう Assignの例です Assignはクラスで インスタンスで初期化します タイプセーフにKeyPathを使います インプットを受信すると オブジェクトに書き込みます 値を書いてる時は エラーを処理できないので エラーの型をNeverにしてあります
動作を見ましょう
サブスクライバーを含む コントローラオブジェクトがあれば パブリッシャーへサブスクライバーを 呼び出し 追加 接続します パブリッシャーが サブスクリプションを送ると サブスクライバーはそれを基に いくつかの値のリクエストを作ります パブリッシャーは同数の値か それ以下の値を送ります パブリッシャーが有限なら 完了かエラーを返します 1つのサブスクリプションに ゼロ以上の値と 完了報告です
今度は オブジェクトを “魔法使い”と名付けました 魔法使いの学年を見てみましょう マーリンは現在5年生です
生徒が学年を修了すると 通知が送られてきて オブジェクトの値を アップデートします NotificationCenterの パブリッシャーのデフォルトを マーリンの進級にします
サブスクライバーのAssignを作り 学年プロパティを更新します
ここでサブスクライブを加えても コンパイルできません 型が合わないからです NotificationCenterは 通知をしますが AssignはIntegerPropertyに 整数型を書きます この2つの間に入って 変換させる何かが必要です それがオペレーターです パブリッシャーのプロトコルを 使っており 宣言型で値型でもあります 値の追加や削除など様々な― 値が変化する動作を決めるものです それを違うパブリッシャーに アップストリームしたり 結果をダウンストリームしたりします
オペレーターの例です Combineでよく使うのが Mapです 接続先のアップストリームと そのアウトプットの変換が Mapの初期値となっています Map自身はエラーがありませんが アップストリームのそれを渡します Notificationと整数型の間に入り 数値を変換します 例です 同じパブリッシャーと サブスクライバーに コンバータを加え graduationPublisherと関連付けます このクロージャが通知を受けると NewGradeを探しにいきます 整数型のNewGradeがあれば その値を返します NewGradeがないか 整数型でなければ デフォルトの0になります クロージャの結果は整数型なので サブスクライバーに つなげられるのです すべてが連動して機能するのです もう少しシンプルな シンタックスをお見せしましょう 動作はこうです
パブリッシャープロトコルの Extensionとして 各オペレータ名を基に 一連の機能を加えました Mapの例です アップストリームを除き Mapを初期化しています パブリッシャーのExtensionは “self”を入れるだけです
一見 ささいなことのようですが これが非同期プログラミングを 一変させるのです 新しいシンタックスを 例で使います
今度はNotificationCenterを graduatedとしました
通知が来たら 同じクロージャで マップさせます これをマーリンの学年にassignします このシンタックスは もっと分かりやすいフローを示します assignはキャンセル可能な リターンをし キャンセルもCombine内でできます パブリッシャーとサブスクライバーの シーケンスを解除できます
このシンタックスが Combineの要です 1つの手順が 次の手順を示していて 最初にパブリッシャーに入れた値を 各オペレーターに従って 変化させます この多数のオペレーターを 宣言型オペレーターAPIと呼んでいます Mapのように機能変化もさせます FilterやReduceもできます リストでパブリッシャーの要素を 表示したり― エラーハンドリングで エラーの初期値化も可能 スレッドやキュー移動は 重たい処理を バックグラウンドに移動させます スケジューリングとタイムは キューの処理や タイマーのサポートをします 多数のオペレーターがあるので 操作が大変そうだと思うかもしれません そういう時はCombineの主眼に戻ります “組み合わせること”です
多くのことができる 少数のオペレーターより それぞれの役割は少ないオペレーターを 多数提供します オペレーターの操作を補助するため 既存のSwiftのAPIから発案しました グラフを想像してください ここに同期型APIと 非同期型APIがあります 上部に1変数が 下部に複数の変数があります Swiftでは1つの同期型整数には intを使います 複数の整数に対しては 配列を使います Combineでは 同じ原理で 非同期型にマップします 非同期型の1変数にはFutureを使い 複数の非同期型変数には パブリッシャーを使います 配列での使い方を知っている オペレーターがあるなら パブリッシャーで試してみましょう 例を見せます
キーが存在しない場合や 整数でない場合は ゼロをデフォルトとします このような値をモデル・オブジェクトに 書き込ませない方がいいので クロージャでnilを返し Filterで排除します Swift 4.1ではcompactMapが 導入されています パブリッシャーも同様で 非常に似た動作をします nilが返ってきたらcompactMapが これを進行中の処理から外します
手順ごとの指示を書いていきましょう
5年生か それ以上の生徒のみを選択するのに Filterを使います この述部に当てはまる要素のみを Filterは通します 配列のFilterと同じです 更に最大3回進級した者に限定します 配列では最初の3つの要素を選ぶのに “prefix”を使います パブリッシャーでも同様に “prefix”を使います 3つの要素を受け取ると 通信をキャンセルし完了報告を送ります
例に戻りましょう パブリッシャーが マーリンの進級を見つけます 彼が進級するとNewGradeを フェッチします その値が5年生より大きく 3回以下であること確認してから マーリンのプロパティに 学年を割り当てます
MapとFilterは優れたAPIですが 同期型向けのものです Combineは非同期型で 力を発揮します 便利なオペレーターを もう2つ紹介しましょう まずはZipです 以前のAppでは ユーザは魔法の杖を作るのに このような時間のかかる 3つの非同期処理が必要でした 処理が終わるまで “次へ”のボタンは出てきません そこでZipの出番です Zipは複数のアップストリームを 1つのタプルに入れます 全アップストリームの インプットが必要なので “これと これと これが終わったら 別のことをする”ようにできます 例えば最初のパブリッシャーが “A”を出し 次のが“1”を出すと 必要な情報が集まり タプルを作ります そして値をサブスクライバーに送ります
App上のZipは 3つのアップストリームを格納し 非同期型の処理の ブーリアン型の回答を待ちます 1つのブーリアンにタプルをマップし “isEnabled”でボタンを有効にします
杖を作る手続きが終わりました 生徒たちは全員 杖を使う前に 条件と規約に同意しなければなりません 3つのスイッチを有効にすると “プレイ”ボタンが押せます 1つでも無効だと ボタンが押せないようにします そこで CombineLatestです Zipと同様 複数のアップストリームを 1つの値にしますが 1つのインプットでも次へ進めます “いずれか実行なら”という処理です 各アップストリームの 最後の値を記憶します それをクロージャにし 1つの値にします
最初のパブリッシャーが“A”を出し 次のが“1”を出したとします クロージャがこれを合体させ 送ります 2つ目のパブリッシャーが 値を変えたので 1つ目の値と合わせた 新しい値を送ります アップストリームが変わるごとに イベントが起きるのです アプリケーションでは CombineLatestを使い 3つが変わると ブーリアンのステートが変わり それを1つの値にして “isEnabled”のプロパティに入れます どれかがfalseなら 結果もfalseで すべてがtrueなら “プレイ”ボタンが押せます
Combineは徐々にアプリケーションに 適応するよう作りました 手始めに すぐ使える Combineの使い方を教えましょう NotificationCenterを使っているなら 通知を受けたら 処理が必要かどうかを決めます Filterを使ってください
複数の非同期型処理の結果を 待っているなら ネットワークオペレーションで Zipを使ってください データを受け取るのに URLSessionを使っていて そのデータを変換するのに JSONDecoderを使っていますか? その処理を手伝うDecodeという オペレーターがあります
今日お話ししたのは 基本的な部分ですが 機能のほんの一部です エラーハンドリングやキャンセル スケジューリングもあり 異なるモジュールで使える デザインパターンもあります SwiftUIにも適用可能です 詳しくは “Combine In Practice”で
ありがとうございました (拍手)
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。