使用 struct id 将收藏夹保存到 UserDefaults
Posted
技术标签:
【中文标题】使用 struct id 将收藏夹保存到 UserDefaults【英文标题】:Saving favorites to UserDefaults using struct id 【发布时间】:2021-02-08 23:54:58 【问题描述】:我正在尝试将用户最喜欢的城市保存在 UserDefaults 中。发现此解决方案保存了结构 ID - 构建并运行但似乎没有保存:在应用重新启动时,先前点击的按钮被重置。
我很确定我错过了什么……
这是我的数据结构和类:
struct City: Codable
var id = UUID().uuidString
var name: String
class Favorites: ObservableObject
private var cities: Set<String>
let defaults = UserDefaults.standard
var items: [City] = [
City(name: "London"),
City(name: "Paris"),
City(name: "Berlin")
]
init()
let decoder = PropertyListDecoder()
if let data = defaults.data(forKey: "Favorites")
let cityData = try? decoder.decode(Set<String>.self, from: data)
self.cities = cityData ?? []
return
else
self.cities = []
func getTaskIds() -> Set<String>
return self.cities
func contains(_ city: City) -> Bool
cities.contains(city.id)
func add(_ city: City)
objectWillChange.send()
cities.contains(city.id)
save()
func remove(_ city: City)
objectWillChange.send()
cities.remove(city.id)
save()
func save()
let encoder = PropertyListEncoder()
if let encoded = try? encoder.encode(tasks)
defaults.setValue(encoded, forKey: "Favorites")
这里是 TestDataView
struct TestData: View
@StateObject var favorites = Favorites()
var body: some View
ForEach(self.favorites.items, id: \.id) item in
VStack
Text(item.title)
Button(action:
if self.favorites.contains(item)
self.favorites.remove(item)
else
self.favorites.add(item)
)
HStack
Image(systemName: self.favorites.contains(item) ? "heart.fill" : "heart")
.foregroundColor(self.favorites.contains(item) ? .red : .white)
【问题讨论】:
【参考方案1】:有几个问题,我将在下面解决。这是工作代码:
struct ContentView: View
@StateObject var favorites = Favorites()
var body: some View
VStack(spacing: 10)
ForEach(Array(self.favorites.cities), id: \.id) item in
VStack
Text(item.name)
Button(action:
if self.favorites.contains(item)
self.favorites.remove(item)
else
self.favorites.add(item)
)
HStack
Image(systemName: self.favorites.contains(item) ? "heart.fill" : "heart")
.foregroundColor(self.favorites.contains(item) ? .red : .black)
struct City: Codable, Hashable
var id = UUID().uuidString
var name: String
class Favorites: ObservableObject
@Published var cities: Set<City> = []
@Published var favorites: Set<String> = []
let defaults = UserDefaults.standard
var initialItems: [City] = [
City(name: "London"),
City(name: "Paris"),
City(name: "Berlin")
]
init()
let decoder = PropertyListDecoder()
if let data = defaults.data(forKey: "Cities")
cities = (try? decoder.decode(Set<City>.self, from: data)) ?? Set(initialItems)
else
cities = Set(initialItems)
self.favorites = Set(defaults.array(forKey: "Favorites") as? [String] ?? [])
func getTaskIds() -> Set<String>
return self.favorites
func contains(_ city: City) -> Bool
favorites.contains(city.id)
func add(_ city: City)
favorites.insert(city.id)
save()
func remove(_ city: City)
favorites.remove(city.id)
save()
func save()
let encoder = PropertyListEncoder()
if let encoded = try? encoder.encode(self.cities)
self.defaults.set(encoded, forKey: "Cities")
self.defaults.set(Array(self.favorites), forKey: "Favorites")
defaults.synchronize()
原版问题:
-
最大的问题是
items
在每次新发布时都会重新创建,City
有一个id
,在创建时分配了一个UUID
。这保证了每次新的发布,每批城市都会有不同的UUID
s,所以储蓄的情况永远不会奏效。
存在一些常见的拼写错误和对实际不存在的属性的引用。
我做了什么:
-
将
cities
和favorites
都设为@Published 属性,这样您就不必手动调用objectWillChange.send
在初始化时,加载城市和收藏夹。这样一来,城市在最初创建后将始终具有相同的 UUID,因为它们是从保存状态加载的
保存时,我同时保存Set
s -- 收藏夹和城市
在原始ForEach
中,我遍历所有cities
,然后只标记属于favorites
的部分
重要提示:在测试时,我发现至少在 Xcode 12.3 / ios 14.3 上,同步到 UserDefaults
是慢,即使使用 now-不推荐的synchronize
方法。我一直想知道为什么当我杀死然后重新打开应用程序时我的更改没有反映出来。最终发现如果我给它大约 10 到 15 秒的时间来同步到 UserDefaults
然后关闭应用程序然后再次打开它,一切都会正常工作。
【讨论】:
感谢您的回复和详细的解释!奇迹般有效。我对错别字不利,因为它是一个更大项目的一部分,我将其分解并更改了名称以使其更简单。我知道问题出在哪里,现在一切都说得通了。非常感谢!以上是关于使用 struct id 将收藏夹保存到 UserDefaults的主要内容,如果未能解决你的问题,请参考以下文章
如何将对象列表中的布尔收藏夹保存到 Flutter 中的共享首选项