![](/img/trans.png)
[英]@Appstorage is not updating based on my picker selection - SwiftUI - WatchApp
[英]SwiftUI, AppStorage and using Picker in TabViews
我正在嘗試使用 AppStorage 跨多個視圖使用選擇器保存少量數據。 但是,我遇到的問題是,當我 select 一個值並鏈接到 AppStorage 時,它會更改所有其他值。 我想要的是為多個視圖中的每個選擇保存值。 如果我使用 @State 變量,選擇工作正常,但當我關閉並重新打開應用程序時,這些值不會被保存。 我很確定我需要將每個選擇發送到它自己的 @AppStorage 變量,但我很難弄清楚如何做到這一點。
struct Animals: Identifiable {
var id = UUID().uuidString
var name: String
var animalTypes: [AnimalTypes]
}
var allAnimals = [
Animals(name: "fred", animalTypes: [.shiba, .lab]),
Animals(name: "barney", animalTypes: [.shiba, .dobberman, .lab]),
Animals(name: "molly", animalTypes: [.snowshoe, .burmese, .bengal]),
Animals(name: "bob", animalTypes: [.burmese]),
Animals(name: "wilma", animalTypes: [.snowshoe, .bengal]),
]
enum AnimalTypes: String, CaseIterable, Codable {
// Dog Breeds
case shiba, lab, dobberman
// Cat Breeds
case snowshoe, burmese, bengal
}
struct AnimalsView: View {
@State var animals: Animals!
var body: some View {
TabView {
ForEach(allAnimals) { animal in
AnimalSelectionView(animals: animal)
.tag(animal.name)
}
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
}
}
struct AnimalSelectionView: View {
@AppStorage("selection") var animalSelection: Int = 0 // Saves the same value across all pickers (how to save individual values?)
// @State private var animalSelection: Int = 0 // Sets value for each picker in each tabview, but doesn't save
@State var animals: Animals!
var body: some View {
VStack {
if animals.animalTypes.count <= 1 {
Text("\(animals.animalTypes[0].rawValue)")
} else {
Text("\(animals.animalTypes[animalSelection].rawValue)")
}
if animals.animalTypes.count > 1 {
Picker(selection: $animalSelection, label: Text("Select Animal Type")) {
ForEach(0 ..< animals.animalTypes.count, id:\.self) { item in
Text("\(item + 1)")
.font(.caption)
}
}
.pickerStyle(SegmentedPickerStyle())
.frame(width: 100, height: 17)
}
}
}
}
我看到您已決定在Animals
class 上創建一個名為id
的屬性。 令人高興的是,這是用於為每個Animals
object 保存唯一的UserDefaults
值的完美工具。
你可以這樣做:
struct AnimalSelectionView: View {
@AppStorage var animalSelection: Int
@State var animals: Animals
init(animals: Animals) {
self.animals = animals
// The below line simply assigns the key which should be used to access your
// desired variable. This way, it can be keyed specifically to your `Animals`
// id value.
self._animalSelection = AppStorage(wrappedValue: 0, "selection-\(animals.id)")
}
...
}
請記住,如果您實例化兩個在 init 中傳遞了相同 arguments 的不同對象,您將無法檢索相同的值。
例子:
let fred = Animals(name: "fred", animalTypes: [.shiba, .lab])
let fred2 = Animals(name: "fred", animalTypes: [.shiba, .lab])
為清楚起見編輯:
在這里, fred
和fred2
基本相同,但每個Animals
實例的id
屬性都不同。 因此,如果您嘗試使用另一個的id
訪問一個的選擇值,您將不會收到正確的值。 您必須保留確切的Animals
實例以訪問您存儲在UserDefaults
中的值,或者至少根據需要保留其id
。 此規則適用於所有應用程序會話。 如果您實例化Animals
object 然后退出並重新啟動應用程序,當重新實例化相同的Animals
object 時,它將根據您的定義分配不同的id
值Animals.id = UUID().uuidString
。
為了在應用程序會話中保留它們的id
,您可以將動物存儲在CoreData
和UserDefaults
中,授予它們 static id
,或者根據Animals
屬性生成一個id
。
創建一個 static id
看起來像這樣:
`Animals(id: "animal-fred", name: "fred", animalTypes: [.shiba, .lab])`
根據它們的屬性生成一個id
可能看起來像:
Animals: Identifiable {
var id: {
// We concatenate the name with each of the `AnimalsTypes`
// by mapping the `AnimalsTypes` to their relevant strings
// and joining them by a comma.
// The resulting `id` might look like:
// "fred-shiba,lab"
return name + "-" + animalTypes.map { $0.rawValue }.joined(separator: ",")
}
var name: String
var animalTypes: [AnimalTypes]
}
基於Animals
屬性生成id
的方法效果很好,盡管如果您創建兩個具有完全相同屬性的Animals
,您的邏輯將無法區分它們,因為它們將生成相同的id
。 然后他們將在UserDefaults
中獲取並設置相同的值,因為他們將共享相同的密鑰。
如果您打算讓這些動物由您的應用程序的用戶動態創建,則需要將它們存儲在CoreData
或UserDefaults
中。 但是,如果您的動物將全部由您創建,您可以靜態定義 ID 或根據Animals
屬性生成它們。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.