View in English

  • メニューを開く メニューを閉じる
  • Apple Developer
検索
検索を終了
  • Apple Developer
  • ニュース
  • 見つける
  • デザイン
  • 開発
  • 配信
  • サポート
  • アカウント
次の内容に検索結果を絞り込む

クイックリンク

5 クイックリンク

ビデオ

メニューを開く メニューを閉じる
  • コレクション
  • トピック
  • すべてのビデオ
  • 利用方法

WWDC19に戻る

ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。

  • 概要
  • トランスクリプト
  • 実践Combine

    経時的に値を処理するためのAppleの新しい統一された宣言型フレームワークであるCombineについて知識を広げましょう。このセッションでは、エラーを適切に処理し、作業のスケジュールを設定し、Appに今すぐCombineを統合する方法を紹介します。

    リソース

      • HDビデオ
      • SDビデオ
    • プレゼンテーションスライド(PDF)

    関連ビデオ

    WWDC19

    • ネットワーキングの最新情報(パート1)
    • 最新のSwift APIのデザイン
    • Combineの紹介
    • iPadで複数のウインドウを使用する
    • macOS向けAppKitの新機能
    • SwiftUIのデータフロー
  • このビデオを検索

    (音楽)

    こんにちは (拍手) Foundationチームの マイケル・リヒューです 本日のテーマは 今年リリースの― Combineフレームワークです トラクターの話ではないです 念のため

    まず Combineとは何か 概要を簡単に説明します

    コードには大抵 値やイベントのPublisherと―

    その値やイベントを 受け取る― Subscriberが 数多く含まれています そして利害関係者が この2者の接続を確立します

    その後 Subscriberは 時として― Publisherから値を受け取ると 宣言します

    するとPublisherは下流に 自由に値を送れます この流れが止まるのは Publisherが送信をやめた時や― 何か失敗があった時や 購読がキャンセルされた時です

    コールバックやクロージャなど 非同期通信の時に― こういう形の通信が ソフトウェアの随所で起こります このパターンこそが Combineです

    経時的に値を処理できるAPIを 記述する― 統一的な抽象概念を Combineで定義します

    値のPublisherを 詳細に見てみましょう

    発表セッションで詳述しましたが おさらいです 値のPublisherは Publisherプロトコルに適合します

    2つのassociatedtypeを 指定します Outputは発行する値の種類で 成功 失敗は関係ありません Failureは後で触れます

    そしてSubscriberとの 接続の仕方を記述します 必須条件は associatedtypeの一致です これだけです 理論は これで十分でしょう セッションのタイトルどおり 実践します

    実にクールな 魔法使いの友達に頼まれ― 魔法学校のアプリケーションを 共同開発します

    このアプリケーションには― 魔法をダウンロードできる機能を 持たせたいのです デベロッパではない彼は― UIコンポーネント代わりの 絵をくれました

    しかし彼はその機能を 実装できるコードを書けるので― 書くつもりです そこで私から Combineを使った― 必要な値の取得の仕方を 解説します このラベルに 魔法の名称を入れるのです

    CombineではNotificationCenterが 通知をサポートします そこで魔法使いが送る通知の Publisherを作成します

    この関数の戻り値の型が Publisherですが 重要なのはPublisherの OutputとFailureの型です

    ここではOutputは“Notification” Failureは“Never” Publisherは 何度も言及しますので― 今後 そのOutputは上に Failureは下に表示することにします

    これが通知のPublisher しかし ダウンロードした魔法を― 記述するデータが必要です

    魔法使いは “データをuserInfo辞書に入れた” Combineにはmapという関数があり この通知を― 必要な形に変換できます これはSequenceの既存の操作と 非常に似ています このPublisherのOutputは“Data” Failureは“Never”です

    mapはPublisherに作用し― 新しいPublisherの operatorを返します operatorは数多くあります

    さらに魔法使いは データについて― “アプリケーションで定義済みの JSON型になる”と それなら別のoperatorで デコードを試せます tryMapです mapと同じですが― Failureに投げられたエラーを 変換する機能が足されています このoperatorのOutputが 魔法のPublisherになります Failureは Errorプロトコルに適合します

    カスタム型のデコードは よくある作業なので― 処理するoperatorを提供します decodeです

    PublisherのOutputは… (拍手) OutputとFailureの型は 同じままです

    失敗するPublisherもあるので 対処法をお話しします

    Combineでは― 失敗への適切な対応が 極めて重要です PublisherもSubscriberも 失敗を記述する可能性があります これを組み込んだのは Swiftと同じく― 規則ベースのエラー処理を 避けたかったから 他の言語では うまくいきませんでした そしてFailureを“Never”と 記述する型が多い 失敗が早い段階で処理されるという 期待を示しています

    我々はNever以外のため 多くのoperatorを提供し― 失敗の対処と 必要なら回復も できるようにします

    簡単なのは“失敗しない”と アサートすることです 返されたPublisherの Failureの型は“Never”になります 理由を見てみましょう

    上流のPublisherと下流のSubscriberを 接続するoperatorが― assertNoFailureだとします このoperatorは 値を受け取れば送ります しかし上流から エラーが届いたら― プログラムがトラップします 魔法使いたちにとって 不本意な結果です

    失敗に対処するoperatorは 豊富にあります assertNoFailure以外に 接続の再試行を試せるoperatorや― エラーの型を変えられる operator 特に有用なのはcatchで― 回復のPublisherを 定義するクロージャを提供でき― 上流のPublisherで 失敗が起きた場合に使います 仕組みを見てみましょう 先ほどと同様ですが 中間のoperatorがcatchです 今度も値は 下流のSubscriberに送られます しかし エラーが届いたら― 既存の上流の接続は 終了します

    次に回復のクロージャを 呼び出し― 新しいPublisherを生成させ 購読すれば― 自由に値を受け取れます 新しいPublisherに置き換えることで エラーから回復できます コードで使ってみましょう

    このクロージャは Publisherを返すことを期待しています

    発行する値が既にあれば 特別なPublisherが定義されます とにかく値を発行するので Justです Combineが最初から備えている 多くのPublisherの1つです これで返されるPublisherの型は “Never”です

    ここまで行った変換を 復習しましょう

    出だしは通知のPublisher データをデコードすべく それをマップしました

    その後 decode operatorを 利用して― データをユーザ定義型に変換 しかし デコードの失敗に備えて― Publisherを プレースホルダに置き換えました

    しかし 待った

    この回復のPublisherでは 通知は二度と見られません その接続は終了しました 出だしのPublisherと接続しながら デコードも試し― プレースホルダも 使いたいのです

    そのためのoperatorも あります flatMapです

    名前のとおり mapのような働きをします しかし新しいPublisherを 生成するようにと― 上流のPublisherが 値をよこします flatMapは この入れ子のPublisherの― 値の送信を細かく処理します 仕組みを見てから コードに戻りましょう

    やはり値は 上流からflatMapに届きます flatMapはクロージャを呼び出し 値を新しいPublisherに変換 この場合はJustです

    やはりdecodeとcatchが 続きます flatMapは新しいPublisherを購読し 値を下流に送ります

    flatMapの 別の値はどうなるか

    今度は このdecodeが エラーを投げると想像しましょう

    それがcatchに届き 回復のPublisherに置き換えられます flatMapに返される Publisherです 従って この処理は 絶対に失敗しません

    コードで使ってみましょう 先ほどの続きです データの流れの 最初のエラーを処理中でした

    今度はflatMapが入りますし ごく単純な変換です やはりJustを使います mapからデコードしたデータで生成した 新しいPublisherです 入れ子スコープを flatMapに使い― 返し デコードし キャッチし flatMapに返します するとflatMapは購読します そのPublisherのFailureは “Never”になります

    失敗を処理できたので 当初の目的を果たしましょう 魔法の名称の発行を 試すことです

    やはり簡単に使える operatorです publisher(for:)です これで型安全なKeypathから ProduceMagicTrickに入り― 新たな 文字列のPublisherを 生成します

    ここで 強力な機能を提供する operatorの種類をご紹介します

    scheduled operatorです スケジューラのように― イベントをいつ どこに送信するか 記述できます

    RunLoopとDispatchQueueが ネイティブにサポートします これらのoperatorは 例えば― delayはイベントの送信を 未来のある時まで延ばします

    throttleはイベントの送信速度を 指定速度未満に抑えます

    receive(on:)を使うと― 下流で受け取ったイベントが 特定のキューで送られます

    これを使い 魔法の名称が メインキューで送られるようにします OutputとFailureの型は 変わりません scheduled operatorの特徴です 他の部分を復習しましょう

    flatMapの先ですね

    Publisher(for:)を使って 魔法の名称を抽出しました

    最後に― receive(on:)で作業を メインスレッドに移します AppKitやUIKitに必要なUIの更新も これで完了です 発行された値は既に 正しいスレッドにあります

    Publisherとoperatorとで 数多くの処理ができました operatorの作り方や 強力に型付けされた値を― 経時的に生成する 付加機能の提供

    PublisherはJustのように 値を同期的に生成できます NotificationCenterのように 非同期的にも

    しかし ここからは 反対側を取り上げます 値の受け取りです Subscriberを取り上げます

    Publisherと同様 2つのassociatedtypeがあります Inputと 失敗の種類のFailureです

    subscription value completionを受け取る― イベント関数を記述します

    この関数の呼び出しの順番は 3つの規則に従っています

    規則1 Publisherが― receive(subscription:)を 1回 呼び出します

    規則2

    Subscriberの要求で Publisherはゼロ以上の値を― 下流に提供できます

    規則3 Publisherはcompletionを 1つ 送信できます そのcompletionは 発行が完了したか― 失敗したことを示します completionが届くと― 値はもう発行されません

    この3つの規則を 要約すると― Subscriberは購読の成功を 1回 知らされ―

    0個以上の値を受け取ります 発行の完了または失敗を 1回 知らされて終了の可能性も “可能性”と言ったのは それが任意だからです データの流れは 無限に続く可能性もあるのです

    Combineでは 多様なSubscriberをサポート 仕組みをお見せします

    Publisherの例に戻りますが 今 知る必要があるのは 使うPublisherの型です 場所を空けましょう

    Subscriberを追加します 非常に簡単な購読方法です assign(to:on:) operatorを使い Keypath代入を追加しました これで上流のPublisherが 発行した値を― 指定オブジェクトのKeypathに 代入できます

    非常に強力な値を どのプロパティにでも代入できます

    このoperatorは購読を キャンセルするトークンも生成できます

    そのキャンセルですが―

    Combineに組み込みました Publisherが イベントの送信を完了する前に― 購読を終了できる方が 好都合だからです 購読の関連リソースを 解放したい場合は特にそうです ベストエフォート型ですが― Subscriberを削除する手段を 提供します

    キャンセルを記述する 新しいプロトコルをご紹介します 極めて有用で便利な AnyCancellableです deinitが呼ばれた時 自動的にcancelを呼ぶので― 明示的にcancelを呼び出す回数が 劇的に減ります Swiftが提供している 強力なメモリ管理機能に頼るだけです

    では2つ目の登録方法に 移ります

    使うoperatorはsinkです 新しい値を受け取った時に 呼び出されるクロージャで― どんな副作用的な処理も できます

    sinkはassignと同様 cancellableを返し― これを使って 購読を終了できます

    3つ目の方法は ハイブリッドです Subjectです Publisherのようにも Subscriberのようにも機能します 値のマルチキャストを サポートしています 特に重要なのは 値を命令的に送らせることです 既存のコードベースを使う際に 最も重要です

    その機能を見てから 使用例を見てみましょう

    Subjectを使うと複数のSubscriberに 送信できることが多い上― 値を命令的に送れます 受け取った値を すべてのSubscriberに送信します

    Publisherが生成する値も 同様です

    Combineでは 2種類のSubjectをサポート Passthroughは 値を保持せず― このSubjectを購読すると 値が表示されます

    もう1つはCurrentValueです 最後に受け取った値の履歴を 保持し― 新規のSubscriberに 追いつかせます

    では今度も あのPublisherの実例です

    このSubjectの生成は 好きな1つを選び― OutputとFailureの型を指定 コンストラクタを呼び出します

    Subjectは 上流のPublisherを購読できます

    Publisherのように― お話ししたsinkなどの operatorを呼び出して― 自身のSubscriberを 形成します

    “please”のような値も 命令的に送れます

    頻繁に届くSubjectを― データの流れに挿入するoperatorも 定義します 例えばPassthroughを挿入する share

    Subjectは非常に強力です クールな使い道が 豊富にありますよ では 4つ目の 最後のSubscriberに移ります

    SwiftUIと統合されています

    SwiftUIはアプリケーション内の 依存関係を記述しさえすれば― あとは処理してくれます

    Combineで言えばデータが いつ どう変更されたか― 記述するPublisherを 提供するだけです

    BindableObjectプロトコルに カスタム型を適合させます

    BindableObjectsの関連型は 1つです

    発行の失敗がない Publisherなので― UIフレームワークでの作業に 最適です この言語の型システムが 上流のエラーの処理を― 強制してくるからです

    最後に didChangeプロパティを 指定します これは型変更を通知するPublisherを 生成します これだけです 詳細はSwiftUI関連の講演を ぜひご覧ください すばらしい処理の数々を 詳しくご説明します ただ ここでも実例を 少々 お見せします

    魔法学校のアプリケーションの モデルから始めて―

    BindableObjectとの 適合性を追加 モデルオブジェクトの変更を Subjectで記述します Subjectは特定の種類の値を 示す必要はありません bodyメソッドから Combineが判断します このSubjectのOutputの型は “Void”にします

    このSubjectは 柔軟性を高めます オブジェクトが変わったら 命令的に通知できるからです

    今は2つのプロパティオブザーバで sendを直接 呼び出し― プロパティの変更時の モデルオブジェクトの変更を示します

    次は このモデルを SwiftUIのViewにフックします 手順は まずモデルを ObjectBindingとして宣言します これでSwiftUIはPublisherを 自動的に見つけ 購読します 次はbodyプロパティから モデルのプロパティを参照します これだけです モデルの変更を知らせるたび SwiftUIは― 自動的に新しいbodyを生成します

    多数の組み込み機能を組み合わせて 非常に強力なものを作成できます 非同期データフローが すばらしいやり方で単純化できるのです これらの優れた機能を 既存のアプリケーションに― さらに組み込む方法を ベンがご説明します (拍手) ありがとう よろしくお願いします

    Combineは 組み合わせていく設計です マイケルの例のとおり― 小さなPublisherを さまざまに変換して― 最終的なPublisherを 作成しました

    例を見てみましょう 魔法学校へのサインアップを アプリケーションに設定します いくつか条件があります まずユーザ名が有効か サーバに確認する

    次はパスワード欄と パスワード確認欄の入力が― 必ず一致することと 8文字以上であることです

    最後に すべての条件を満たしたら― UIを有効か無効にできること これは非同期動作の例です デバイス限定の同期動作が あるので― 組み合わせられるようにします 例を見てみましょう

    まずInterface Builderで target-actionを― パスワード欄の 値変更プロパティに構築

    それをコードで使うと― ユーザが入力したら シグナルを受け取れます 現在の値の テキストプロパティを受け取り ivarに格納します

    しかし組み合わせたいのは 先にお話しした同期動作です その方法は? 本当に簡単です プロパティにPublishedを足せば Publisherを追加できます

    Publishedはプロパティラッパーで Swift 5.1の― 新機能を使います

    では簡単な例で 使い方を見てみましょう

    Publishedは プロパティの前に追加されます

    コード内では 前と変わりません

    これを保持して 文字列値を取得します この場合 currentPasswordは “1234”です

    ドル記号の接頭辞で参照すると 特殊化します ラップされた値に アクセスしています

    Publisherで使うか それを購読する operatorが使えます この場合はsinkです

    もう1つの“password”に そのプロパティを再設定したら―

    Subscriberが 変更された値を取得 この人物は パスワード衛生に無頓着です

    2つのPublisherを 同時に評価させます

    足したのは Publishedプロパティと― 2つのPublisherと 発行された文字列です

    検証済みのパスワードを 1つ発行するものが要ります

    そのためのoperatorが CombineLatestです

    2つのプロパティがあります そのプロパティラッパーを CombineLatestで参照でき―

    どちらかが変われば シグナルを受け取ります 例えばパスワード欄に 既に入力されていて― 確認欄に入力するとします passwordAgainは変わりますが 入力されたpasswordは元のまま

    次にクロージャで ビジネス要件を満たします “一致するか 8文字を超えているか”

    不一致ならnilを返し― 他のシグナルと使用して フォームが有効かを判断します nilをシグナルとして使います

    そして型を見ると― それまで踏んできた手順が 分かります 読み方はコードと同じです 2つの発行された文字列の 最新の値を結合し― 任意の文字列が 1つできました

    しかし この悪いパスワードを 使わせないために― mapを追加したら? 型が変わります 2つの発行された文字列の 最新の値を結合し― 任意の文字列をもたらすよう マップしました ほぼすべてのユースケースの デバッグに最適です しかし これは API境界として通知しており― 他のPublisherと組み合わせたい そこで何が重要か絞ると― 失敗しない 任意の文字列のPublisherです そのためのoperatorが eraseToAnyPublisherです 任意の文字列“Never”の AnyPublisherを返します

    型は変わっていません これでAPI境界のために欲しい契約を 通知でき― 実装の詳細をすべて隠せます

    ここまでは最初のプロパティ つまり文字列を取得し― Publishedで 文字列のPublisherを追加しました

    次にCombineLatestで Publisherの最新の値を結合し― ビジネスロジックを追加

    次に悪いパスワードを mapを使って除外し 最後が―

    eraseToAnyPublisherです API境界で 他のものと組み合わせるからです

    1つ目のPublisherです

    次に進みます

    モデル化したい 非同期アクティビティです ユーザ名が有効か サーバに確認しますが― ユーザの入力は速いです

    Publishedを 文字列プロパティストレージに追加し 値変更プロパティの target-actionをフックします ただ 少々特殊なのは― ネットワーク操作を 1文字ごとに発生させたくないこと スパム行為になります もう少し間隔を空けたい

    そこでdebounceです debounceを使うと 値を受け取り かつ― 速く受け取らないウィンドウを 指定できます 例として 仕組みを見てみましょう 入力欄になる 上流のPublisherがあります そして中央にdebounce ユーザの入力が速いと― シグナルの送信も速い しかし1つのシグナルずつに できます

    もっといいやり方もあります

    そのウィンドウで入力し 値が最後に同じになるなら― 同じユーザ名が有効か 何度も確認しなくていい 例えば“Merlin”と 入力するとします “n”を消して また“n”を入力したら― やはり“Merlin”ですから removeDuplicatesで 処理できます ウィンドウ内で同じ値が 何度も発行されないようにします

    ユーザ名プロパティに コードでPublishedを追加し―

    debounceで シグナルの間隔を空け― 全く同じ値を除外します

    しかし まだ非同期処理をしていません 目的はサーバに 有効か確認することです

    そこで既存の関数 usernameAvailableを― Publisherとして使います

    マイケルの例で 学びましたが― flatMapを使うと 新しいPublisherを返せます

    どうやって呼び出すか

    そのためにあるのが Futureです promiseを取るクロージャを 与えます promiseは成功か失敗の 結果を受け取るクロージャです

    使うのはとても簡単です usernameAvailable関数を呼び出し 非同期処理が完了したら― この場合 promiseは“成功”になります 前と同じく 失敗したらnilです

    手順の確認です 最初は単純なPublisher usernameでした debounceでシグナルの間隔を開き 同じものを除外

    非同期ネットワーク呼び出しを行う 既存のAPIを次にFutureでラップ flatMapで データの流れをフォークしました

    それがAPI境界なので eraseToAnyPublisherを使いました 今度は2つの カスタムPublisherを使います validatedPasswordと validatedUsernameです

    この2つを組み合わせます

    目的は2つのシグナル つまりデバイス限定シグナルと 非同期ネットワーク呼び出しで― UIを有効または無効にします やり方は分かっています

    CombineLatestで 今の2つのPublisherを取得します 確認し オプションとして 完全な認証情報のタプルを返すか― そうでなければnilを返します

    UIに配線するにはsignupButtonに アウトレットを配線します

    この購読を保持するivarを 作成します ビューコントローラで 保持するためです フォームの表示中は ボタンを有効か無効にしたいので

    そこで保存します ブール値にマップして― ボタンのisEnabledプロパティに 代入します

    receive(on:)で メインのRunLoopに切り替えます UIコードに必要な操作です assign operatorで signupButtonのKeypathに代入します

    部品がそろいました

    最初は文字列を発行するだけの 3つの単純なPublisher

    それから組み合わせを利用し― 小さな手順から積み上げて 最終的なチェーンを作成し 組み合わせてボタンに代入 これがCombineです

    今すぐ始めましょう カスタムなPublisherにして― 小さなPublisherに分けられる ロジックを特定 組み合わせて すべてを1つにつないでいきます 追加的に導入できます 一気に変更する必要もなく 組み合わせられます Futureは 既に持っているものを― 導入できます

    コールバックなどを 組み合わせられます

    詳しくは入門編の講演や― SwiftUI関連の講演を ご覧ください AppKitのラボもあります 以上です (拍手)

Developer Footer

  • ビデオ
  • WWDC19
  • 実践Combine
  • メニューを開く メニューを閉じる
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    メニューを開く メニューを閉じる
    • アクセシビリティ
    • アクセサリ
    • App Extension
    • App Store
    • オーディオとビデオ(英語)
    • 拡張現実
    • デザイン
    • 配信
    • 教育
    • フォント(英語)
    • ゲーム
    • ヘルスケアとフィットネス
    • アプリ内課金
    • ローカリゼーション
    • マップと位置情報
    • 機械学習
    • オープンソース(英語)
    • セキュリティ
    • SafariとWeb(英語)
    メニューを開く メニューを閉じる
    • 英語ドキュメント(完全版)
    • 日本語ドキュメント(一部トピック)
    • チュートリアル
    • ダウンロード(英語)
    • フォーラム(英語)
    • ビデオ
    Open Menu Close Menu
    • サポートドキュメント
    • お問い合わせ
    • バグ報告
    • システム状況(英語)
    メニューを開く メニューを閉じる
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles(英語)
    • フィードバックアシスタント
    メニューを開く メニューを閉じる
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program(英語)
    • News Partner Program(英語)
    • Video Partner Program(英語)
    • セキュリティ報奨金プログラム(英語)
    • Security Research Device Program(英語)
    Open Menu Close Menu
    • Appleに相談
    • Apple Developer Center
    • App Store Awards(英語)
    • Apple Design Awards
    • Apple Developer Academy(英語)
    • WWDC
    Apple Developerアプリを入手する
    Copyright © 2025 Apple Inc. All rights reserved.
    利用規約 プライバシーポリシー 契約とガイドライン