🦋
SwiftUI: Hashableに適当に対応すると意図しない挙動になりうる
記事としては後でまとめる。とりあえずコードを貼る。
以下のコードでユーザーがボタンを押したりトグルスイッチを切り替えても動かないUIが生成される。
import SwiftUI
struct Hoge: Hashable {
let id = UUID()
var flag: Bool = false
var number: Int = 0
static func == (lhs: Hoge, rhs: Hoge) -> Bool {
return lhs.id == rhs.id
}
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
struct InnerView: View {
@Binding var flag: Bool
@Binding var number: Int
var body: some View {
HStack {
Toggle(isOn: $flag) {
Image(systemName: "flag.circle.fill")
}
Button {
number += 1
} label: {
Image(systemName: "plus.app.fill")
}
}
}
}
struct ContentView: View {
@State var hoge = Hoge()
var body: some View {
VStack {
Text(hoge.flag.description)
Text(hoge.number.description)
InnerView(flag: Binding(get: { hoge.flag }, set: { v, _ in hoge.flag = v }),
number: Binding(get: { hoge.number }, set: { v, _ in hoge.number = v }))
}
.padding(20)
}
}
実験
struct
の==
の内容をもっと厳密にしたら意図通りには動いた。
struct Hoge: Hashable {
let id = UUID()
var flag: Bool = false
var number: Int = 0
static func == (lhs: Hoge, rhs: Hoge) -> Bool {
return lhs.id == rhs.id && lhs.flag == rhs.flag && lhs.number == rhs.number
}
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
Discussion