iOS编辑器错误。archivedData更名

17

请帮帮我!我被困在一个循环中,无法找到出路。我正在尝试为工作学习IOS编程,所以我想从他们的教程应用程序“餐单列表”开始。我已经到了保存持久性数据的部分,但现在编辑器让我陷入了一个无尽的循环。我有一行代码...

let isSuccessfulSave = NSKeyedArchiver.archiveRootObject(meals, toFile: Meal.ArchiveURL.path)

那给我一个警告,说...

'archiveRootObject(_:toFile:)' 在iOS 12.0中已弃用:请使用+archivedDataWithRootObject:requiringSecureCoding:error:代替

好的,我把这行代码改成...

let isSuccessfulSave = NSKeyedArchiver.archivedDataWithRootObject(meals)

接着就提示我...

'archivedDataWithRootObject'已经被重命名为'archivedData(withRootObject:)'。

好的,因此我将代码行更改为...

let isSuccessfulSave = NSKeyedArchiver.archivedData(withRootObject: meals)

这告诉我“archivedData(withRootObject :)”已在iOS 12.0中弃用:改用+archivedDataWithRootObject:requiringSecureCoding:error:代替。

'archivedData(withRootObject:)'被弃用了,现在需要使用+archivedDataWithRootObject:requiringSecureCoding:error:代替。

好的...所以...archivedData已经被弃用了,我必须使用archivedDataWithRootObject,但是使用archivedDataWithRootObject已经被重命名为archivedData,但是archivedData已经被弃用了,所以要使用被重命名为archivedData的archivedDataWithRootObject,它又被弃用了...如此无限循环。

我尝试查看开发者文档,但它们只告诉我同样的事情,其中一个已被弃用,没有链接或任何东西。搜索谷歌只给我一堆页面展示使用它们的语法。我仍然是IOS编程的新手,不知道如何摆脱这个无休止的弃用到重命名到弃用的循环中...

请帮忙,我迷失了方向,不确定如何继续。谢谢。


另一个需要问的问题是,在Swift中为什么要使用NSKeyedArchiver?为什么不使用基于Codable的现代Swift API呢? - rmaddy
1
以上两条评论都是垃圾,首先应该在代码中避免使用过时的方法,其次答案与问题所在领域密切相关。 - Shehata Gamal
2
@matt,所以你建议一个完全新手的程序员忽略警告并且不问问题吗?谢谢,这很有帮助。我不会IOS编程。 - Neglected Sanity
1
我想说的是不要称之为 bug,也不要发泄情绪。只需要问一下就好了。 - matt
2
我理解并且道歉,我只是不知道如何描述它。编辑器没有帮助,因为它只会让我陷入循环,而文档对于一个完全新的IOS开发者来说非常无用。我并没有完全理解整个“requireingSecureCoding:error:”的部分,所以对于一个完全的新手来说,它看起来就像一个bug,你会被困在一个循环中。 - Neglected Sanity
4个回答

25

我正在按照您试图完成的相同的示例进行操作,并且我找出了如何更新在iOS 12中存储和检索值的方法,这应该会对您有所帮助:

//MARK: Private Methods
private func saveMeals() {

    let fullPath = getDocumentsDirectory().appendingPathComponent("meals")

    do {
        let data = try NSKeyedArchiver.archivedData(withRootObject: meals, requiringSecureCoding: false)
        try data.write(to: fullPath)
        os_log("Meals successfully saved.", log: OSLog.default, type: .debug)
    } catch {
        os_log("Failed to save meals...", log: OSLog.default, type: .error)
    }
}

func getDocumentsDirectory() -> URL {
    let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    return paths[0]
}

private func loadMeals() -> [Meal]? {
    let fullPath = getDocumentsDirectory().appendingPathComponent("meals")
    if let nsData = NSData(contentsOf: fullPath) {
        do {

            let data = Data(referencing:nsData)

            if let loadedMeals = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? Array<Meal> {
                return loadedMeals
            }
        } catch {
            print("Couldn't read file.")
            return nil
        }
    }
    return nil
}

此外,您会发现需要将ViewDidLoad更新为以下内容:
override func viewDidLoad() {
    super.viewDidLoad()

    // Use the edit button item provided by the table view controller.
    navigationItem.leftBarButtonItem = editButtonItem

    let savedMeals = loadMeals()

    if savedMeals?.count ?? 0 > 0 {
        meals = savedMeals ?? [Meal]()
    } else {
        loadSampleMeals()
    }

}

我希望这可以帮助你,对我来说应用程序现在可以工作,存储和检索数据。

顺便说一下:这不适用于Xcode 11 beta和iOS 13,它应该适用于这些版本之前的任何版本。


5
iOS 12 的通用解决方案如下:

一个通用的解决方案可以是:

class SettingsArchiver {
    static func setData(_ value: Any, key: String) {
        let ud = UserDefaults.standard
        let archivedPool = try? NSKeyedArchiver.archivedData(withRootObject: value, requiringSecureCoding: true)
        ud.set(archivedPool, forKey: key)
    }

    static func getData<T>(key: String) -> T? {
        let ud = UserDefaults.standard
        if let val = ud.value(forKey: key) as? Data,
            let obj = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(val) as? T {
            return obj
        }
        return nil
    }
}

2

你需要的是

try {
   let data = try NSKeyedArchiver.archivedData(withRootObject:meals,requiringSecureCoding:true)
   try data.write(to:fullPath)
}
catch {
   print(error)
}

这里在文档中提到,它适用于IOS 11及以上版本。


原始调用中的“toFile”部分怎么样了?现在全部放到同一个位置了吗?我不得不在我的餐食类中添加静态成员... static let DocumentsDirectory = FileManager().urls(for: .documentDirecory, in: .userDomainMask).first! static let ArchiveURL = DocumentsDirectory.appendingPathComponent("meals") - Neglected Sanity
是的,但它已被弃用。您需要使用答案中的安全选项,并将返回的数据写入文件。 - Shehata Gamal
那么在运行archivedData函数之后,我仍然需要将数据写入文件吗?我不知道该怎么做。他们的教程显然已经过时了,并告诉你使用已弃用的方法来自动写入文件。 - Neglected Sanity
检查一下我的答案,伙计。 - user2430797

1
我认为,直接回答您的问题的答案是使用 Meal.swift 数据模型中定义的 ArchiveURL(考虑 MVC 模式),并在您的 MealTableViewController.swift 控制器中重新实现 saveMeals() 函数,使用推荐的替代方法来替换已弃用的 archiveRootObject 方法,具体如下:
private func saveMeals(){
    do {
        let data = try NSKeyedArchiver.archivedData(withRootObject: meals, requiringSecureCoding: true)
        try data.write(to: Meal.ArchiveURL)
    }
    catch {
        print("Couldn't save to file")
    }
}

虽然这个答案有点晚 :-) 我希望它能帮助任何遇到这个问题的人。

此外,您还需要在Meal类声明中添加“NSSecureCoding”,以及以下变量声明:“static var supportsSecureCoding: Bool = true”。 - user2430797

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接