Saving custom Swift class with NSCoding to UserDefaults Saving custom Swift class with NSCoding to UserDefaults swift swift

Saving custom Swift class with NSCoding to UserDefaults


In Swift 4 or higher, Use Codable.

In your case, use following code.

class Blog: Codable {   var blogName: String?}

Now create its object. For example:

var blog = Blog()blog.blogName = "My Blog"

Now encode it like this:

if let encoded = try? JSONEncoder().encode(blog) {    UserDefaults.standard.set(encoded, forKey: "blog")}

and decode it like this:

if let blogData = UserDefaults.standard.data(forKey: "blog"),    let blog = try? JSONDecoder().decode(Blog.self, from: blogData) {}


The first problem is you have to ensure that you have a non-mangled class name:

@objc(Blog)class Blog : NSObject, NSCoding {

Then you have to encode the object (into an NSData) before you can store it into the user defaults:

ud.setObject(NSKeyedArchiver.archivedDataWithRootObject(blog), forKey: "blog")

Similarly, to restore the object you'll need to unarchive it:

if let data = ud.objectForKey("blog") as? NSData {    let unarc = NSKeyedUnarchiver(forReadingWithData: data)    unarc.setClass(Blog.self, forClassName: "Blog")    let blog = unarc.decodeObjectForKey("root")}

Note that if you're not using it in the playground it's a little simpler as you don't have to register the class by hand:

if let data = ud.objectForKey("blog") as? NSData {    let blog = NSKeyedUnarchiver.unarchiveObjectWithData(data)}


As @dan-beaulieu suggested I answer my own question:

Here is the working code now:

Note: Demangling of the class name was not necessary for the code to work in Playgrounds.

import Foundationclass Blog : NSObject, NSCoding {    var blogName: String?    override init() {}    required init(coder aDecoder: NSCoder) {        if let blogName = aDecoder.decodeObjectForKey("blogName") as? String {            self.blogName = blogName        }    }    func encodeWithCoder(aCoder: NSCoder) {        if let blogName = self.blogName {            aCoder.encodeObject(blogName, forKey: "blogName")        }    }}let ud = NSUserDefaults.standardUserDefaults()var blog = Blog()blog.blogName = "My Blog"ud.setObject(NSKeyedArchiver.archivedDataWithRootObject(blog), forKey: "blog")if let data = ud.objectForKey("blog") as? NSData {    let unarc = NSKeyedUnarchiver(forReadingWithData: data)    let newBlog = unarc.decodeObjectForKey("root") as Blog}