4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【SwiftUI】Bindableプロパティラッパー

Last updated at Posted at 2023-09-21

この記事は何?

SwiftUIフレームワークのBindableについて、Appleの開発者向けドキュメントを独自に解説する。

Swiftを基礎から学ぶには
自著、工学社より発売中の「まるごと分かるSwiftプログラミング」をお勧めします。変数、関数、フロー制御構文、データ構造はもちろん、構造体からクロージャ、エクステンション、プロトコル、クロージャまでを基礎からわかりやすく解説しています。

Bindable構造体

「観測可能なオブジェクトにある変数プロパティへの参照」のバインディングを作成するプロパティラッパー型。

宣言
@dynamicMemberLookup @propertyWrapper
struct Bindable<Value>

概要

@Bindableプロパティラッパーを使用すると、Observableプロトコルに準拠したデータモデルオブジェクトの変数プロパティへのバインディングを作成できる。

単純なケース

以下の例において、データモデルのBookクラスは「信頼できる情報源」。
そして、BookEditViewビューは変数book@Bindableをマークしている。
そのbodyでは、TextFieldビューがbookのバインドを利用して、titleプロパティを変更する。
また、ToggleビューはbookisAvailableプロパティを変更する。
ここでは、各プロパティのバインディングを渡すために、どちらのコントロールビューに対しても$構文を使用している点に注目。

// 観測可能なオブジェクトのデータモデル
@Observable
class Book: Identifiable {
    var title = "Sample Book Title"
    var isAvailable = true
}

// 図書の情報を編集するためのビュー
struct BookEditView: View {
    @Bindable var book: Book    // bookは信頼できる情報源にバインド
    @Environment(\.dismiss) private var dismiss
        
    // TextFieldとToggleは「bookへのバインド」を受け取る
    var body: some View {
        Form {
            TextField("Title", text: $book.title)
            Toggle("Book is available", isOn: $book.isAvailable)
            Button("Close") {
                dismiss()
            }
        }
    }
}

上のコードにおいて、ビューのプロパティとして作成されるバインド変数には、既定値を設定しない点に注意。
実際のインスタンスは、親ビューから渡される。

ケース2

Bindableプロパティラッパーは、Observableオブジェクトの変数およびプロパティにも使用できる。
これにはグローバル変数や「SwiftUIの外部にある型のプロパティ」だけでなく、ローカル変数が含まれる。

例えば、以下のLibraryViewビューはbody内で@Bindable変数を作成する。
ボディのリスト内でバインド変数を作成することによって、それぞれの要素を参照するバインドを取得できる。

struct LibraryView: View {
    // Book型インスタンスはObservableなデータモデル
    @State private var books = [Book(), Book(), Book()]

    var body: some View {
        List(books) { book in
            @Bindable var book = book
            TextField("Title", text: $book.title)
        }
    }
}

ここではまた、@Bindableな変数に既定値を設定している点に注目できる(最初のケースでは既定値を設定していない)。
@Bindableな変数bookは「bookデータモデルに接続するバインディング」を提供するので、TextFieldビューは「モデルデータのtitleプロパティ」にアクセスして、変更を加えることができる。

ケース3

ケース2と同じ手法を、「観測可能なオブジェクトへのバインディング」がビューの環境に格納されている場合も使用できる。

例えば、次のコードは@Environment()プロパティラッパーを使用して、環境にあるObservableBook型インスタンスを取得する。
そして、ビューのbody内で@Bindableな変数bookを作成して、$記号をマークして「bookデータモデルのtitleプロパティまでのバインディング」をTextFieldビューに渡す。

struct TitleEditView: View {
    // bookプロパティに「ビューの環境にあるモデルデータ」を取得
    @Environment(Book.self) private var book

    var body: some View {
        @Bindable var book = book    // 環境にあるモデルデータの参照をバインド
        TextField("Title", text: $book.title)
    }
}

ここでもやはり、バインド変数に既定値を設定する必要がある。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?