Car.swift:
//
// Car.swift
// SwiftArchiverDemo
//
// Created by Tom Limbaugh on 6/7/14.
//
import Foundation
protocol NSCoding {
}
class Car:NSObject {
var year: Int = 0
var make: String = ""
var model: String = ""
init() {
super.init()
}
func encodeWithCoder(aCoder: NSCoder!) {
aCoder.encodeInteger(year, forKey:"year")
aCoder.encodeObject(model, forKey:"make")
aCoder.encodeObject(make, forKey:"model")
}
init(coder aDecoder: NSCoder!) {
super.init()
year = aDecoder.decodeIntegerForKey("year")
make = aDecoder.decodeObjectForKey("make") as String
model = aDecoder.decodeObjectForKey("model") as String
}
}
main.swift creates three instances of the Car class for demonstrating the archiving and unarchiving of the objects.
//
// main.swift
// SwiftArchiverDemo
//
// Created by Tom Limbaugh on 6/7/14.
//
import Foundation
var documentDirectories:NSArray
var documentDirectory:String
var path:String
var unarchivedCars:NSArray
var allCars:NSArray
// Create a filepath for archiving.
// Get document directory from that list
// append with the .archive file name
var car1:Car! = Car()
var car2:Car! = Car()
var car3:Car! = Car()
// The 'archiveRootObject:toFile' returns a bool indicating
// whether or not the operation was successful. We can use that to log a message.
if NSKeyedArchiver.archiveRootObject(allCars, toFile: path) {
// Now lets unarchive the data and put it into a different array to verify
// that this all works. Unarchive the objects and put them in a new array
unarchivedCars = NSKeyedUnarchiver.unarchiveObjectWithFile(path) as NSArray
// Output the new array
}
// main.swift
// SwiftArchiverDemo
//
// Created by Tom Limbaugh on 6/7/14.
//
var documentDirectory:String
var path:String
var unarchivedCars:NSArray
var allCars:NSArray
documentDirectories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
documentDirectory = documentDirectories.objectAtIndex(0) as String
path = documentDirectory.stringByAppendingPathComponent("swift_archiver_demo.archive")
var car2:Car! = Car()
var car3:Car! = Car()
car1.year = 1957
car1.make = "Chevrolet"
car1.model = "Bel Air"
car2.year = 1964
car2.make = "Dodge"
car2.model = "Polara"
car3.year = 1972
car3.make = "Plymouth"
car3.model = "Fury"
allCars = [car1, car2, car3]
// whether or not the operation was successful. We can use that to log a message.
if NSKeyedArchiver.archiveRootObject(allCars, toFile: path) {
println("Success writing to file!")
} else {
println("Unable to write to file!")
}// that this all works. Unarchive the objects and put them in a new array
unarchivedCars = NSKeyedUnarchiver.unarchiveObjectWithFile(path) as NSArray
for car : AnyObject in unarchivedCars {
println("Here's a \(car.year) \(car.make) \(car.model)")}
As with the original Objective-C post, if you’re running this as a command line tool, your *.archive file should be found in your '/Users/username/Documents directory'. If you open it with TextEdit.app, you should see a cryptic representation of the string data from the original objects.
Do these functions get called automatically or do we need to make an explicit call ?
ReplyDeletefunc encodeWithCoder(aCoder: NSCoder!) {...}
init(coder aDecoder: NSCoder!) {...}
Some protocols have required methods or functions. These are both required methods/functions in the NSCoding Protocol. So, you must call/implement these methods/functions.
DeleteFrom the Xcode documentation -
"The NSCoding protocol declares the two methods that a class must implement so that instances of that class can be encoded and decoded."
If you are retrieving data from a file, you must init(coder decoder: NSCoder!) to instantiate the objects that you are decoding. The Swift call omits the word 'With' in init methods/functions. In Objective-C the call looks like this: - (id)initWithCoder:(NSCoder *)decoder
Hi, I get a few errors in the main.swift file. Any thoughts?
ReplyDeleteInsert the keyword 'override', before calling 'init'. Apparently, this was not necessary in an earlier beta version of Xcode. The compiler should have suggested that. It did on my end and works fine now. The init method should now look like this:
ReplyDeleteoverride init() {
super.init()
}
Thanks. I figured out that I also had to make to downcast as follows:
ReplyDeletefor car in unarchivedCars as [Car!] {
println("Here's a \(car.year) \(car.make) \(car.model)")
}
Hi, I think there was a change made to the NSCoding protocol. See here:
ReplyDeletehttp://stackoverflow.com/questions/25750088/swift-does-not-conform-to-protocol-nscoding
Basically, take out the ! in both methods and add 'required' to init(coder aDecoder: NSCoder)
Thanks for posting this. I have OSX 10.9 installed so I had to copy the 10.10 SDK from the Xcode 6 Beta for my current Xcode 6 GM installation. This is necessary for any Swift OSX command line tools that I build on my machine. That being said, The code above still compiles and runs on my machine as written, with the August 9, 2014 edit from above. So, If I understand correctly, the SDK that ships with OSX 10.10 would have made your changes necessary.
ReplyDelete