我有一个包含交易类别的类(请参阅下面的示例代码),用户可以在设置过程中从中选择一个子集以在应用程序中使用。稍后在事务输入期间,如果未选择类中的第一个类别(在设置期间)并且选择器状态参数初始化为零,我会看到控制台消息“选择器:选择“0”无效并且没有关联的标签,这将给出未定义的结果”。事实上,如果状态参数初始化为 5 并且在设置过程中未选择第 5 个类别,它也会给出相同的警告。
我的问题是如何初始化状态参数,这样我就不会收到此选择器警告?
从控制台消息中我认为问题出在 ForEach 循环而不是条件。但如果删除条件if categories.catItem[item].catInUse == true {,我就看不到警告。
例如,在下面的代码中,如果在应用程序设置期间未选择类别Cat A(catInUse 为 false)并且交易条目选择器状态参数为,
@State private var entryCat: Int = 0我将看到上面的控制台警告消息。类别Cat A仍然在列表中 - 只是没有显示。
struct getCategory: View {
@EnvironmentObject var categories: Categories
@State private var entryCat: Int = 0
var body: some View {
Section(header: Text("Select Category")) {
Picker(selection: $entryCat, label: Text("")) {
ForEach(0 ..< categories.catItem.count, id: \.self) { item in
if categories.catItem[item].catInUse == true {
Text(categories.catItem[item].catName)
.bold()
}
}
}.pickerStyle(MenuPickerStyle())
}
}
}
// working categories
struct CatModel: Codable, Identifiable, Hashable {
var id = UUID()
var catNum: Int // used by setup categories
var catName: String // category name
var catTotal: Double // category total
var catBudget: Double // category budget
var catPix: String // sf symbol
var catInUse: Bool // catInUse: true = category in use
var catCustom: Bool // true = custom category (can be deleted)
}
class Categories: ObservableObject {
@Published var catItem: [CatModel] {
didSet { // save categories
if let encoded = try? JSONEncoder().encode(catItem) {
UserDefaults.standard.set(encoded, forKey: StorageKeys.workCat.rawValue)
}
}
}
var catCount: Int = 0
init() {
// read in category data
if let catItem = UserDefaults.standard.data(forKey: StorageKeys.workCat.rawValue) {
if let decoded = try? JSONDecoder().decode([CatModel].self, from: catItem) {
self.catItem = decoded
return
}
}
catItem = []
let item0 = CatModel(catNum: 0, catName: "Cat A", catTotal: 0.0, catBudget: 0, catPix: "a.circle", catInUse: false, catCustom: false)
self.catItem.append(item0)
let item1 = CatModel(catNum: 1, catName: "Cat B", catTotal: 0.0, catBudget: 0, catPix: "b.circle", catInUse: false, catCustom: false)
self.catItem.append(item1)
let item2 = CatModel(catNum: 2, catName: "Cat C", catTotal: 0.0, catBudget: 0, catPix: "c.circle", catInUse: false, catCustom: false)
self.catItem.append(item2)
let item3 = CatModel(catNum: 3, catName: "Cat D", catTotal: 0.0, catBudget: 0, catPix: "d.circle", catInUse: false, catCustom: false)
self.catItem.append(item3)
let item4 = CatModel(catNum: 4, catName: "Cat E", catTotal: 0.0, catBudget: 0, catPix: "e.circle", catInUse: false, catCustom: false)
self.catItem.append(item4)
let item5 = CatModel(catNum: 5, catName: "Cat F", catTotal: 0.0, catBudget: 0, catPix: "f.circle", catInUse: false, catCustom: false)
self.catItem.append(item5)
}
}
Run Code Online (Sandbox Code Playgroud)
我会避免使用索引来访问数组,而是使用 for every 循环。由于如果没有任何类别正在使用或值为 0 的类别未使用,您可能没有任何对象可供预选,因此我建议改用可选的选择属性。
最好将选择属性的类型设置为标识符而不是整个类型,并且由于您的模型符合,Identifiable因此 id 是一个不错的选择。
@State private var entryCat: CatModel.ID?
Run Code Online (Sandbox Code Playgroud)
另外,由于您想过滤模型对象,我更喜欢在计算属性中执行此操作,但当然直接在 中执行ForEach也是一种选择
var categoryList: [CatModel] {
return categories.catItem.filter(\.catInUse)
}
Run Code Online (Sandbox Code Playgroud)
然后选择器代码可以更改为
Picker("", selection: $entryCat) {
Text("<Nothing selected>").tag(nil as CatModel.ID?)
ForEach(categoryList) { category in
Text(category.catName)
.tag(Optional(category.id))
}
}.pickerStyle(MenuPickerStyle())
Run Code Online (Sandbox Code Playgroud)
Text第一个来表示为零时的状态entryCat,即没有选择任何内容。tag保存用于设置的标识符entryCatentryCat是可选的,因此标签值也必须是可选的以匹配类型有点偏离主题,但关于命名类型的一些建议,类型名称应该以大写字母开头,所以我会使用 GetCategory,模型的好名称是名词,不要缩写它,所以在这里我会使用 Category 而不是 CatModel
| 归档时间: |
|
| 查看次数: |
2682 次 |
| 最近记录: |