问题复现
在学习Picker绑定tag时,发现存在下述报错问题。
报错提示:
完整问题代码
import SwiftUI
// 定义一个自定义水果对象
struct Fruit: Identifiable {
let id = UUID() // 唯一标识符
let name: String // 水果名称
let color: String // 水果颜色
}
struct FruitPicker: View {
@State private var selectedFruitId: UUID // 绑定的是水果的唯一ID
let fruits = [
Fruit(name: "Apple", color: "Red"),
Fruit(name: "Banana", color: "Yellow"),
Fruit(name: "Orange", color: "Orange")
]
var body: some View {
VStack {
Picker("Select a fruit", selection: $selectedFruitId) {
ForEach(fruits) { fruit in
// 显示水果名称,但使用水果的唯一ID作为 tag
Text(fruit.name).tag(fruit.id)
}
}
.pickerStyle(WheelPickerStyle())
if let selectedFruit = fruits.first(where: { $0.id == selectedFruitId }) {
Text("Selected fruit: \(selectedFruit.name), Color: \(selectedFruit.color)")
} else {
Text("No fruit selected")
}
}
}
}
#Preview {
FruitPicker(selectedFruitId: Fruit(name: "Apple", color: "Red").id)
}
经排查发现问题为selectedFruitId字段是@State属性,因为@State属性是SwiftUI用来管理视图状态的特殊属性,因此它是私有的。所以,Swift UI不允许从视图外直接初始化它的值,这也意味着,我们无法通过下面的代码
FruitPicker(selectedFruitId: Fruit(name: "Apple", color: "Red").id)
从外部传一个初始值给selectedFruitId,因此触发报错提示。
解决方案
正因为@State的特殊性,我们需要给@State属性一个默认值,
1、selectedFruitId改为可选类型,因此不需要从外部传参。
@State private var selectedFruitId: UUID? // 绑定的是水果的唯一ID
2、通过onAppear方法给selectedFruitId传参
.onAppear {
selectedFruitId = fruits.first?.id
}
修改完这两部分后,我们发现
if let selectedFruit = fruits.first(where: { $0.id == selectedFruitId }) {
Text("Selected fruit: \(selectedFruit.name), Color: \(selectedFruit.color)")
} else {
Text("No fruit selected")
}
这段代码不会跟着我们的Picker选择器变化。
这作为本次报错所延伸的另一个问题,问题出现在下面这段代码中:
Picker("Select a fruit", selection: $selectedFruitId) {
ForEach(fruits) { fruit in
// 显示水果名称,但使用水果的唯一ID作为 tag
Text(fruit.name).tag(fruit.id)
}
}
.pickerStyle(WheelPickerStyle())
这个问题在于Picker的selection绑定的是selectedFruitId,因为我们调整selectedFruitId为可选。因此,我们在Picker的tag选项也必须是可选类型的UUID?,只有这样才能让与selection绑定的值类型一致。
Picker("Select a fruit", selection: $selectedFruitId) {
ForEach(fruits) { fruit in
// 显示水果名称,但使用水果的唯一ID作为 tag
Text(fruit.name).tag(fruit.id as UUID?)
}
}
.pickerStyle(WheelPickerStyle())
按照上述操作全部修改后,问题得到解决。
完整代码
import SwiftUI
// 定义一个自定义水果对象
struct Fruit: Identifiable {
let id = UUID() // 唯一标识符
let name: String // 水果名称
let color: String // 水果颜色
}
struct FruitPicker: View {
@State private var selectedFruitId: UUID? // 绑定的是水果的唯一ID
let fruits = [
Fruit(name: "Apple", color: "Red"),
Fruit(name: "Banana", color: "Yellow"),
Fruit(name: "Orange", color: "Orange")
]
var body: some View {
VStack {
Picker("Select a fruit", selection: $selectedFruitId) {
ForEach(fruits) { fruit in
// 显示水果名称,但使用水果的唯一ID作为 tag
Text(fruit.name).tag(fruit.id as UUID?)
}
}
.pickerStyle(WheelPickerStyle())
if let selectedFruit = fruits.first(where: { $0.id == selectedFruitId }) {
Text("Selected fruit: \(selectedFruit.name), Color: \(selectedFruit.color)")
} else {
Text("No fruit selected")
}
}
.onAppear {
selectedFruitId = fruits.first?.id
}
}
}
#Preview {
FruitPicker()
}