Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IOS editor bug. archivedData renamed

Please help me! I am stuck in a loop and can't find my way out. I am trying to learn IOS programming for work so I thought I would start with their tutorial app the Meal list application. I am at the part where you are supposed to start saving persistent data and now the editor has me stuck in a never ending loop. I have a line of code...

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

That gives me a warning that says...

'archiveRootObject(_:toFile:)' was deprecated in iOS 12.0: Use +archivedDataWithRootObject:requiringSecureCoding:error: instead

OK, so I change the line of code to...

let isSuccessfulSave = NSKeyedArchiver.archivedDataWithRootObject(meals)

Which then gives me the warning...

'archivedDataWithRootObject' has been renamed to 'archivedData(withRootObject:)'

OK, so I change the line of code to...

let isSuccessfulSave = NSKeyedArchiver.archivedData(withRootObject: meals)

Which tells me...

'archivedData(withRootObject:)' was deprecated in iOS 12.0: Use +archivedDataWithRootObject:requiringSecureCoding:error: instead

OK... So... archivedData was deprecated and I have to use archivedDataWithRootObject, but using archivedDataWithRootObject has been renamed to archivedData, but archivedData is deprecated so use archivedDataWithRootObject which is renamed to archivedData which is deprecated... ad infinitum.

I have tried looking on the developer docs but they just tell me the same thing, one is deprecated, with no links or anything and searching google just gives me a bunch of pages showing me the syntax of using any of them. I am still really new to IOS programming and have no idea how to get out of this endless loop of deprecated to renamed to deprecated to...

Please help, I am lost and not sure how to continue. Thank you.

like image 805
Neglected Sanity Avatar asked Nov 17 '18 01:11

Neglected Sanity


Video Answer


2 Answers

I am following the same example you are trying to do, and I figured out how to update the methods for storing and retrieving values in iOS 12, this should help you:

//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
}

Also you will find that you need to update ViewDidLoad as this:

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()
    }

}

I hope this helps, for me the app is now working, storing and retrieving data.

FYI: This doesn't work with Xcode 11 beta and iOS 13 is should work with anything before those versions.

like image 174
Daspuru Avatar answered Oct 24 '22 11:10

Daspuru


A general solution for iOS 12 would be:

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
    }
}
like image 45
Ani Farsh Avatar answered Oct 24 '22 10:10

Ani Farsh