有时,UserDefaults 会在重新启动应用程序后重新加载已删除的数据
Sometimes, UserDefaults reloads the deleted data after relaunching the app
我在对 save/load 数据使用 UserDefaults 时发现了一个奇怪的行为,我的操作如下。
- 滑动即可删除 tableView 中的 data/row。
- 重新启动应用程序以再次从 UserDefaults 加载数据。
- 我尝试了很多次并同时使用模拟器和 iPhone,有时当应用程序重新启动时删除的行会再次显示。
嗯,这是一个随机问题,我检查了我的代码但没有找到线索。我的数据模型非常简单,因此应该可以快速保存和加载。可以给我一些吗hint/advice?
型号
class Note: Codable {
var content: String
init(content: String) {
self.content = content
}
}
ViewController
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
...
var notes = [Note]()
override func viewDidLoad() {
super.viewDidLoad()
...
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
loadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return notes.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.accessoryType = .disclosureIndicator
let node = notes[indexPath.row].content
cell.textLabel?.text = node
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = DetailViewController()
vc.bodyText = notes[indexPath.row].content
navigationController?.pushViewController(vc, animated: true)
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
notes.remove(at: indexPath.row)
print("notes: \(notes)")
saveData()
tableView.deleteRows(at: [indexPath], with: .fade)
count = notes.count
}
}
@objc func createNewNote() {
let vc = NewNoteViewController()
vc.notes = notes
navigationController?.pushViewController(vc, animated: true)
}
func loadData() {
DispatchQueue.global().async { [weak self] in
let defaults = UserDefaults.standard
if let savedNotes = defaults.object(forKey: "notes") as? Data {
let jsonDecoder = JSONDecoder()
do {
self?.notes = try jsonDecoder.decode([Note].self, from: savedNotes)
print("Load notes: \(String(describing: self?.notes))")
DispatchQueue.main.async {
self?.tableView.reloadData()
self?.count = self?.notes.count ?? 0
}
} catch {
print("Failed to load notes")
}
}
}
}
func saveData() {
DispatchQueue.global().async { [weak self] in
let jsonEncoder = JSONEncoder()
if let savedData = try? jsonEncoder.encode(self?.notes) {
let defaults = UserDefaults.standard
defaults.set(savedData, forKey: "notes")
print("value saved")
} else {
print("Failed to save notes")
}
}
}
}
UserDefaults
不会立即将数据写入磁盘,出于性能原因,它会等待执行批量写入。
如果您通过 Xcode 重新启动应用程序,它可能会在应用程序有机会保留更改之前终止应用程序。
尝试强制关闭设备上的应用程序,而不是使用 Xcode 重新启动,或者再等几秒钟再重新启动,这不应该发生。
明确地说,您所看到的不是问题,这是您启动应用程序的方式的副作用。别担心,安装后它不会影响您的应用程序的工作方式。
有可能 [weak self] 在异步任务有机会 运行 之前被处理掉。
尝试将 self.notes
作为参数传递给 saveData(_ notes: [Note]) 而不是通过闭包内的 self?.notes
访问它。
这里可能有点过头了,但你可能想看看:
Extending Your App's Background Execution Time
我在对 save/load 数据使用 UserDefaults 时发现了一个奇怪的行为,我的操作如下。
- 滑动即可删除 tableView 中的 data/row。
- 重新启动应用程序以再次从 UserDefaults 加载数据。
- 我尝试了很多次并同时使用模拟器和 iPhone,有时当应用程序重新启动时删除的行会再次显示。
嗯,这是一个随机问题,我检查了我的代码但没有找到线索。我的数据模型非常简单,因此应该可以快速保存和加载。可以给我一些吗hint/advice?
型号
class Note: Codable {
var content: String
init(content: String) {
self.content = content
}
}
ViewController
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
...
var notes = [Note]()
override func viewDidLoad() {
super.viewDidLoad()
...
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
loadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return notes.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.accessoryType = .disclosureIndicator
let node = notes[indexPath.row].content
cell.textLabel?.text = node
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = DetailViewController()
vc.bodyText = notes[indexPath.row].content
navigationController?.pushViewController(vc, animated: true)
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
notes.remove(at: indexPath.row)
print("notes: \(notes)")
saveData()
tableView.deleteRows(at: [indexPath], with: .fade)
count = notes.count
}
}
@objc func createNewNote() {
let vc = NewNoteViewController()
vc.notes = notes
navigationController?.pushViewController(vc, animated: true)
}
func loadData() {
DispatchQueue.global().async { [weak self] in
let defaults = UserDefaults.standard
if let savedNotes = defaults.object(forKey: "notes") as? Data {
let jsonDecoder = JSONDecoder()
do {
self?.notes = try jsonDecoder.decode([Note].self, from: savedNotes)
print("Load notes: \(String(describing: self?.notes))")
DispatchQueue.main.async {
self?.tableView.reloadData()
self?.count = self?.notes.count ?? 0
}
} catch {
print("Failed to load notes")
}
}
}
}
func saveData() {
DispatchQueue.global().async { [weak self] in
let jsonEncoder = JSONEncoder()
if let savedData = try? jsonEncoder.encode(self?.notes) {
let defaults = UserDefaults.standard
defaults.set(savedData, forKey: "notes")
print("value saved")
} else {
print("Failed to save notes")
}
}
}
}
UserDefaults
不会立即将数据写入磁盘,出于性能原因,它会等待执行批量写入。
如果您通过 Xcode 重新启动应用程序,它可能会在应用程序有机会保留更改之前终止应用程序。
尝试强制关闭设备上的应用程序,而不是使用 Xcode 重新启动,或者再等几秒钟再重新启动,这不应该发生。
明确地说,您所看到的不是问题,这是您启动应用程序的方式的副作用。别担心,安装后它不会影响您的应用程序的工作方式。
有可能 [weak self] 在异步任务有机会 运行 之前被处理掉。
尝试将
self.notes
作为参数传递给 saveData(_ notes: [Note]) 而不是通过闭包内的self?.notes
访问它。这里可能有点过头了,但你可能想看看: Extending Your App's Background Execution Time