How to archive and unarchive an SKPhysicsBody array using UserDefaults since iOS 12.0

89 views Asked by At

I can successfully archive and unarchive an array of SKPhysicsBody's using UserDefaults as below but the unarchive process has been deprecated. This is the warning message... 'unarchiveObject(with:)' was deprecated in iOS 12.0: Use +unarchivedObjectOfClass:fromData:error: instead. I have been going round and round in circles with this and still not working. How would I conform to this? my code is below.

To archive...

do { try UserDefaults.standard.set(NSKeyedArchiver.archivedData(withRootObject:Sat1shapes,requiringSecureCoding:true), forKey: "Sat1shapes")
 }
catch { 
print(error)}

To unarchive...

var Sat1shapes: [SKPhysicsBody] = []
                
if let dataObject = UserDefaults.standard.value(forKey: "Sat1shapes") as? NSData {
                    Sat1shapes = NSKeyedUnarchiver.unarchiveObject(with: dataObject as Data) as! [SKPhysicsBody]
                    }

Here is the updated code that avoids warning but it is not storing the [SKPhysicsBody] array as with the deprecated version.

var Sat1shapes: [SKPhysicsBody] = []
        
         let dataObject = UserDefaults.standard.value(forKey: "Sat1shapes") as? NSData
        do  {
            Sat1shapes = try NSKeyedUnarchiver.unarchivedObject(ofClasses: [NSArray.self, SKPhysicsBody.self], from: dataObject! as Data) as! [SKPhysicsBody]
            
            } catch {
                print(error)
            }
   
1

There are 1 answers

4
z2k On

Something like this. Look into each step in the process to figure out where you are having trouble.

func writeBody(_ body: SKPhysicsBody) {
    do {
        // Convert from SKPhysicsBody to Data
        let data = try NSKeyedArchiver.archivedData(withRootObject: body, requiringSecureCoding: false)
        // Write Data instance into UserDefaults
        UserDefaults.standard.set(data, forKey: "body")
        print("Wrote body: \(String(reflecting: body))")
    } catch {
        print("Failed to write body: \(error.localizedDescription)")
    }
}

func readBody() -> SKPhysicsBody? {
    // Read body from UserDefaults (as Data).
    guard let dataObject = UserDefaults.standard.object(forKey: "body") else {
        print(#"No data was stored in UserDefaults under "body" key"#)
        return nil
    }
    
    guard let data = dataObject as? Data else {
        print(#"Object stored in UserDefaults "body" key is not Data type."#)
        return nil
    }
    
    do {
        return try NSKeyedUnarchiver.unarchivedObject(ofClass: SKPhysicsBody.self, from: data)
    } catch {
        print("Failed to unarchive SKPhysicsBody from Data: \(error.localizedDescription)")
        return nil
    }
}

Update: adding array variant

func writeBodies(_ bodies: [SKPhysicsBody]) {
    do {
        // Convert from SKPhysicsBody to Data
        let data = try NSKeyedArchiver.archivedData(withRootObject: bodies, requiringSecureCoding: false)
        // Write Data instance into UserDefaults
        UserDefaults.standard.set(data, forKey: "bodies")
        print("Wrote bodies: \(String(reflecting: bodies))")
    } catch {
        print("Failed to write bodies: \(error.localizedDescription)")
    }
}

func readBodies() -> [SKPhysicsBody]? {
    // Read body from UserDefaults (as Data).
    guard let dataObject = UserDefaults.standard.object(forKey: "bodies") else {
        print(#"No data was stored in UserDefaults under "bodies" key"#)
        return nil
    }
    
    guard let data = dataObject as? Data else {
        print(#"Object stored in UserDefaults "bodies" key is not Data type."#)
        return nil
    }
    
    do {
        return try NSKeyedUnarchiver.unarchivedArrayOfObjects(ofClass: SKPhysicsBody.self, from: data)
    } catch {
        print("Failed to unarchive SKPhysicsBody from Data: \(error.localizedDescription)")
        return nil
    }
}