I\'m having trouble using NSCoding
in Swift. I have attempted to implement the protocol but I get a crash whenever I call my save()
method. Xcode p
Here is another example with an object called SNStock
that has two string properties, ticker
and name
:
import Foundation
class SNStock: NSObject, NSCoding {
let ticker: NSString
let name: NSString
init(ticker: NSString, name: NSString) {
self.ticker = ticker
self.name = name
}
// MARK: NSCoding
required init(coder aDecoder: NSCoder) {
self.ticker = aDecoder.decodeObjectForKey("ticker") as! NSString
self.name = aDecoder.decodeObjectForKey("name") as! NSString
}
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(ticker, forKey: "ticker")
aCoder.encodeObject(name, forKey: "name")
}
// MARK: NSObjectProtocol
override func isEqual(object: AnyObject?) -> Bool {
if let object = object as? SNStock {
return self.ticker == object.ticker &&
self.name == object.name
} else {
return false
}
}
override var hash: Int {
return ticker.hashValue
}
}
class Student: NSObject, NSCoding {
var name: String!
var className: String!
var rollNo: Int!
var marks: [Float]!
// MARK: NSCoding
required convenience init(coder decoder: NSCoder) {
self.init()
self.name = decoder.decodeObjectForKey("name") as String?
self.className = decoder.decodeObjectForKey("className") as String?
self.rollNo = decoder.decodeIntegerForKey("rollNo")
self.marks = decoder.decodeObjectForKey("marks") as [Float]!
}
func encodeWithCoder(coder: NSCoder) {
coder.encodeObject(self.name, forKey: "name")
coder.encodeObject(self.className, forKey: "className")
coder.encodeInt(Int32(self.rollNo), forKey: "rollNo")
coder.encodeObject(self.marks, forKey: "marks")
}
}
Above class string,integer,array encoding are implemented.
suppose student is an instance of class Student
Archiving
File system :
NSKeyedArchiver.archiveRootObject(student, toFile: "Here give your file path")
NSUserDefaults :
let data = NSKeyedArchiver.archivedDataWithRootObject(student)
NSUserDefaults.standardUserDefaults().setObject(data, forKey: "student")
Unarchiving
File system :
NSKeyedUnarchiver.unarchiveObjectWithFile(student, toFile: "Here give your file path")
NSUserDefaults :
if let data = NSUserDefaults.standardUserDefaults().objectForKey("student") as? NSData {
let student = NSKeyedUnarchiver.unarchiveObjectWithData(data)
}
Addit:
File path for saving / reading
func saveFileLocation() -> String {
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let documentDirectory = paths[0] as! String
return documentDirectory.stringByAppendingPathComponent("savefile")
}
Quite a bit has changed with Swift since this question was asked. I can't reproduce the error you're seeing, but I was able to get NSCoding to work with Swift 1.0 with the code below.
class CourseList: NSObject, NSCoding
{
var myCourses: Dictionary<String, String>?
override init() {}
required init(coder aDecoder: NSCoder) {
self.myCourses = aDecoder.decodeObjectForKey("myCourses") as? Dictionary
}
func encodeWithCoder(aCoder: NSCoder) {
if let courses = self.myCourses{
aCoder.encodeObject(courses, forKey: "myCourses")
}
}
func populateCourses() {
self.myCourses = ["cs101": "Hello World"]
}
func save() {
let data = NSKeyedArchiver.archivedDataWithRootObject(self)
NSUserDefaults.standardUserDefaults().setObject(data, forKey: "courseList")
}
func clear() {
NSUserDefaults.standardUserDefaults().removeObjectForKey("courseList")
}
class func loadSaved() -> CourseList? {
if let data = NSUserDefaults.standardUserDefaults().objectForKey("courseList") as? NSData {
return NSKeyedUnarchiver.unarchiveObjectWithData(data) as? CourseList
}
return nil
}
}
To load a saved instance or create a new one if needed
// Try loading a saved version first
if let courseLs = CourseList.loadSaved() {
println("loaded Save CourseList")
} else {
// Create a new Course List
let courseLs: CourseList = CourseList()
courseLs.populateCourses()
courseLs.save()
}
The following code does not work
class Hero : AnyObject, NSCoding {
var heroID: String?
var title: String?
var imageName: String?
var detail: String?
var star: String?
init() {
}
func update(_ dictionary: Dictionary<String, AnyObject>) {
heroID = dictionary["imageName"] as? String
title = dictionary["title"] as? String
imageName = dictionary["imageName"] as? String
detail = dictionary["detail"] as? String
star = dictionary["star"] as? String
}
required init?(coder aDecoder: NSCoder) {
heroID = aDecoder.decodeObject(forKey: "heroID") as? String
title = aDecoder.decodeObject(forKey: "title") as? String
imageName = aDecoder.decodeObject(forKey: "imageName") as? String
detail = aDecoder.decodeObject(forKey: "detail") as? String
star = aDecoder.decodeObject(forKey: "star") as? String
}
func encode(with aCoder: NSCoder) {
aCoder.encode(heroID, forKey: "heroID")
aCoder.encode(title, forKey: "title")
aCoder.encode(imageName, forKey: "imageName")
aCoder.encode(detail, forKey: "detail")
aCoder.encode(star, forKey: "star")
}
}
Be sure to write like this
class Hero : NSObject, NSCoding {
var heroID: String?
var title: String?
var imageName: String?
var detail: String?
var star: String?
override init() {
}
}