如何解决尝试在Swift中持久保存数据时,NSKeyedArchiver无法保存或加载数据
我一直在使用Apple的Developer教程来开发基本的iOS Food Tracker。当我进入“持久数据”步骤时,我意识到所使用的功能已被弃用,因此我在网上搜索以找到更新/工作版本。我找到了一些有用的NSKeyedArchiver / Unarchiver教程,但是我的代码仍然出现错误。既然有很多问题,我一直很难找到问题的根源(是在存档数据吗?正在取消存档?我使用了错误的存档URL?是在完全不同的地方出现错误吗?)。
这是我第一次在StackOverflow上提问,我急于寻求帮助。这段代码确实使我无所适从,直觉告诉我,由于对Swift / Xcode的了解有限,这可能是一个简单的问题,而我却错过了。我已经测试了许多不同版本的NSKeyedArchiver,我想知道它可能是设置还是参数。
class MealTableViewController: UITableViewController {
//MARK: Properties
var meals = [Meal]()
override func viewDidLoad() {
super.viewDidLoad()
// Use the edit button item provided by the table view controller.
navigationItem.leftBarButtonItem = editButtonItem
// Load any saved meals,otherwise load sample data
if let savedMeals = loadMeals() {
os_log("saved meals equals load meals")
meals += savedMeals
}
else {
// Load the sample data.
loadSampleMeals()
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView,numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation,return the number of rows
return meals.count
}
override func tableView(_ tableView: UITableView,cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Table view cells are reused and should be dequeued using a cell identifier
let cellIdentifier = "MealTableViewCell"
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier,for: indexPath) as? MealTableViewCell else {
fatalError("The dequeued cell is not an instance of MealTableViewCell")
}
// Fetches the appropriate meal for the data source layout.
let meal = meals[indexPath.row]
cell.nameLabel.text = meal.name
cell.photoImageView.image = meal.photo
cell.ratingControl.rating = meal.rating
return cell
}
// Override to support conditional editing of the table view.
override func tableView(_ tableView: UITableView,canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
// Override to support editing the table view.
override func tableView(_ tableView: UITableView,commit editingStyle: UITableViewCell.EditingStyle,forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// Delete the row from the data source
meals.remove(at: indexPath.row)
saveMeals()
tableView.deleteRows(at: [indexPath],with: .fade)
} else if editingStyle == .insert {
// Create a new instance of the appropriate class,insert it into the array,and add a new row to the table view
}
}
/*
// Override to support rearranging the table view.
override func tableView(_ tableView: UITableView,moveRowAt fromIndexPath: IndexPath,to: IndexPath) {
}
*/
/*
// Override to support conditional rearranging of the table view.
override func tableView(_ tableView: UITableView,canMoveRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the item to be re-orderable.
return true
}
*/
// MARK: - Navigation
// In a storyboard-based application,you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue,sender: Any?) {
super.prepare(for: segue,sender: sender)
switch(segue.identifier ?? ""){
case "AddItem":
os_log("Adding a new meal.",log: oslog.default,type: .debug)
case "ShowDetail":
guard let mealDetailViewController = segue.destination as? MealViewController else{
fatalError("Unexpected destination: \(segue.destination)")
}
guard let selectedMealCell = sender as? MealTableViewCell else{
fatalError("Unexpected sender: \(String(describing: sender))")
}
guard let indexPath = tableView.indexPath(for: selectedMealCell) else{
fatalError("The selected cell is not being displayed by the table")
}
let selectedMeal = meals[indexPath.row]
mealDetailViewController.meal = selectedMeal
default:
fatalError("Unexpected Segue Identifier; \(String(describing: segue.identifier))")
}
}
//MARK: Private Methods
private func loadSampleMeals(){
let burger = UIImage(named: "burger")
let sandwich = UIImage(named: "sandwich")
let coffee = UIImage(named: "coffee")
let pizza = UIImage(named: "pizza")
guard let meal1 = Meal(name: "Burger",photo: burger,rating: 4) else{
fatalError("Unable to instantiate burger")
}
guard let meal2 = Meal(name: "Sandwich",photo: sandwich,rating: 2) else{
fatalError("Unable to instantiate sandwich")
}
guard let meal3 = Meal(name: "Coffee",photo: coffee,rating: 5) else{
fatalError("Unable to instantiate coffee")
}
guard let meal4 = Meal(name: "Pizza",photo: pizza,rating: 4) else{
fatalError("Unable to instantiate pizza")
}
meals += [meal1,meal2,meal3,meal4]
}
private func saveMeals() {
do {
let mealData = try NSKeyedArchiver.archivedData(withRootObject: meals,requiringSecureCoding: true)
try mealData.write(to: Meal.ArchiveURL)
print(mealData)
os_log("Meals successfully saved.",type: .debug)
} catch {
os_log("Failed to save meals...",type: .error)
}
}
//MARK: Actions
@IBAction func unwindToMealList(sender: UIStoryboardSegue) {
if let sourceViewController = sender.source as? MealViewController,let meal = sourceViewController.meal {
if let selectedindexPath = tableView.indexPathForSelectedRow{
// Update an existing meal.
meals[selectedindexPath.row] = meal
tableView.reloadRows(at: [selectedindexPath],with: .none)
}
else {
// Add a new meal.
let newIndexPath = IndexPath(row: meals.count,section: 0)
meals.append(meal)
tableView.insertRows(at: [newIndexPath],with: .automatic)
}
// Save the meals.
saveMeals()
}
}
private func loadMeals() -> [Meal]? {
do {
let fileData = try Data(contentsOf: Meal.ArchiveURL)
let loadedStrings = try NSKeyedUnarchiver.unarchivedobject(ofClass: Meal.self,from: fileData)
print("unarchived Strings worked")
} catch {
// print("Couldn't read file. \(error)")
print("Couldn't find file.")
print(Meal.ArchiveURL)
}
return meals
}
}
private func saveMeals() {
do {
let mealData = try NSKeyedArchiver.archivedData(withRootObject: meals,requiringSecureCoding: true)
try mealData.write(to: Meal.ArchiveURL)
print(mealData)
os_log("Meals successfully saved.",type: .debug)
} catch {
os_log("Failed to save meals...",type: .error)
}
}
当要尝试“尝试NSKeyedArchiver.archivedData(withRootObject:餐,需要SecureeCoding:true)”时,它立即转到“捕获”位置,我不确定为什么。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。