Sponsor Link
環境&対象
- macOS Big Sur 11.4
- Xcode 13.0 beta
- iOS 15.0 beta
配列を Binding で渡す
#以前の記事でも書きましたが、WWDC21 での発表に合わせたアップデートです。
SwiftUI を使っていると List, ForEach 等のループ内に、配列の Binding を渡したいケースが発生します。
以下は、以前の記事です。
[SwiftUI] SwiftUIのForEach内でBinding変数を渡したい
StackOverflow 等でもよく質問が出ていて、色々な方法が説明されていましたが、どれも 直接的に記述している感じがしないものでした。(declarative なはずなのに)
SwiftUI の次のバージョンでは、解決策が実装されそうなので、その内容を説明します。
以下では、iOS15 で対応する予定の SwiftUI を “次期バージョンの SwiftUI”、iOS14 までの SwiftUI を “これまでの SwiftUI” と書いています。
なお、次期バージョンの SwiftUI は、現在ベータ版ですので、リリース時には変更が入っているかもしれません。
前提
複数の要素を配列で持ち、その内容を TextField や Slider で編集したいとします。以下のような例です。
iOS14 以前のバージョンの SwiftUI での実装
以前は、以下のように実装していました。
//
// ContentView.swift
//
// Created by : Tomoaki Yagishita on 2021/06/17
// © 2021 SmallDeskSoftware
//
import SwiftUI
struct SliderItem: Identifiable {
public var id: UUID
public var doubleValue: Double
init() {
id = UUID()
doubleValue = Double.random(in: 0...10)
}
}
struct ContentView: View {
@State var items:[SliderItem] = [SliderItem(), SliderItem(), SliderItem(), SliderItem()]
var body: some View {
VStack {
List(items.indices) { index in
Text("\(items[index].doubleValue)")
Slider(value: $items[index].doubleValue, in: 0...10)
}
}
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
配列の indices を使って、ループさせます。ループの中では、index を使用して配列から要素のデータや Binding を取得しています。
WWDC21 のビデオでも言及していますが、この方法は、お勧めしないと説明されています。
これまでは、indices を使った実装しかできなかったのですが、次期バージョンの SwiftUI では この indices を使った実装はお勧めしないということだと思います。
# ちなみに、identifier をきちんと制御しなさいということも言われていますので、この記事の例では、Double を保持するためにも ID を振ってサンプルを作ってみました。
次期バージョンの SwiftUI での実装
見た目は同じなので省略です。
以下のコードのように、List に対して、配列の Binding を渡すことができるようになります。
//
// ContentView.swift
//
// Created by : Tomoaki Yagishita on 2021/06/17
// © 2021 SmallDeskSoftware
//
import SwiftUI
struct SliderItem: Identifiable {
public var id: UUID
public var doubleValue: Double
init() {
id = UUID()
doubleValue = Double.random(in: 0...10)
}
}
struct ContentView: View {
@State var items:[SliderItem] = [SliderItem(), SliderItem(), SliderItem(), SliderItem()]
var body: some View {
VStack {
// (1) (2)
List($items) { $item in
Text("\(item.doubleValue)") // (3)
Slider(value: $item.doubleValue, in: 0...10) // (4)
}
}
.padding()
}
}
- List に対して、配列の Binding を渡すことができます
- 渡された 配列の要素を、Binding で受けることができます
- 値を使用したい時は変数として使えます
- Binding として使いたい時は、(これまでと同様に) $ をつけて使います
上記では、List をコード例に使っていますが、ForEach に対しても同様に渡すことができます。
まとめ:SwiftUI の List/ForEach に Binding を渡す方法
以前からも indices を使えばできることでしたが、Binding を List に渡すように記述することで、その List で行いたいことが明確に記述されるようになったと思います。
- List に Binding を渡すことできる
- closure 内には、配列要素の Binding が渡される
- closure 内での扱いは、これまで通り
説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。
Sponsor Link