I am new to programming. I am making a little database program for iOS in swift.
I have a person class:
class Person : NSObject {
var firstName : String
var lastName : String
init (firstName : String, lastName : String) {
self.firstName = firstName
self.lastName = lastName
}
}
I declare an array of the class at the top of my view controller:
var peopleArray = [Person]()
I then fill the array by declaring some sample users and append it to the array:
var nateB = Person(firstName: "Nate", lastName: "Birkholz")
var nateC = Person(firstName: "Nate", lastName: "Carson")
var nateD = Person(firstName: "Nate", lastName: "Donnelly")
self.peopleArray.append(nateB)
self.peopleArray.append(nateC)
self.peopleArray.append(nateD)
I then try to save the data to a plist file:
let fileManager = (NSFileManager.defaultManager())
let directorys : [String]? = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory,NSSearchPathDomainMask.AllDomainsMask, true) as? [String]
if (directorys != nil){
let directories:[String] = directorys!;
let pathToFile = directories[0]; //documents directory
let plistfile = "PeopleArray.plist"
let plistpath = pathToFile.stringByAppendingPathComponent(plistfile);
if !fileManager.fileExistsAtPath(plistpath){
println("Declaring cocoaArray")
var cocoaArray : NSArray = peopleArray
cocoaArray.writeToFile(plistpath, atomically: true)
println("I wrote an array to the file at\n\n\(plistpath)")
}
The plist file isn't created, it silently fails to create and the function completes as if it had. Any thoughts?
The obscure compatibility processes of the swift data types and data structures with the cocoa classes is frustrating to me. I just want to save a danged file. I also can't use the "append" function if I declare my array as an NSArray, nor can I += an item into the array...
Update:
I added the following functions to my Person class:
func encodeWithCoder(aCoder: NSCoder!) {
aCoder.encodeObject(firstName, forKey:"firstName")
aCoder.encodeObject(lastName, forKey:"lastName")
}
init (coder aDecoder: NSCoder!) {
self.firstName = aDecoder.decodeObjectForKey("firstName") as String
self.lastName = aDecoder.decodeObjectForKey("lasName") as String
}
Saving the file is now:
let fileManager = (NSFileManager.defaultManager())
let directorys : [String]? = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory,NSSearchPathDomainMask.AllDomainsMask, true) as? [String]
println("value of directorys is \(directorys)")
if (directorys != nil){
let directories:[String] = directorys!;
let pathToFile = directories[0]; //documents directory
let plistfile = "PeopleArray.plist"
let plistpath = pathToFile.stringByAppendingPathComponent(plistfile);
if !fileManager.fileExistsAtPath(plistpath){ //writing Plist file
self.createInitialPeople()
println("Declaring cocoaArray")
var cocoaArray : NSArray = [NSKeyedArchiver.archivedDataWithRootObject(peopleArray)]
println("writing to path")
cocoaArray.writeToFile(plistpath, atomically: true)
let tellMe = cocoaArray.writeToFile(plistpath, atomically: true)
println("Return of write is \(tellMe)")
}
A Plist file with inscrutable data is created.
I close the app and start it again, i then try too load the file:
else { //Reading Plist file
println("\n\nPlist file found at \(plistpath)")
let cocoaArray = NSMutableArray.arrayWithContentsOfFile(plistpath)
peopleArray = cocoaArray as Array
}
}
And I fail because I cannot downcast "AnyObject is not identical to 'Person'. I have tried downcasting it in several ways and just cannot do so successfully. This is really frustrating.
After you added the following functions to your Person class:
func encodeWithCoder(aCoder: NSCoder!) {
aCoder.encodeObject(firstName, forKey:"firstName")
aCoder.encodeObject(lastName, forKey:"lastName")
}
init (coder aDecoder: NSCoder!) {
self.firstName = aDecoder.decodeObjectForKey("firstName") as String
self.lastName = aDecoder.decodeObjectForKey("lasName") as String
}
You should use 【NSKeyedArchiver】 and 【NSKeyedUnarchiver】 to store and fetch the array.
Thanks @Anthony Kong.
His answer helps a lot, but I think the following codes can really solve the problem.
TO STORE THE ARRAY IN PLIST
let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory,NSSearchPathDomainMask.AllDomainsMask, true)
let path: AnyObject = paths[0]
let arrPath = path.stringByAppendingString("/array.plist")
NSKeyedArchiver.archiveRootObject(peopleArray, toFile: arrPath)
TO FETCH THE ARRAY FORM PLIST
if let tempArr: [Person] = NSKeyedUnarchiver.unarchiveObjectWithFile(arrPath) as? [Person] {
peopleArray = tempArr
}
First of all, the root cause is [NSArray writeToFile:atomically:]
only supports certain data types. You can check the documentation here.
If you print out the return code from cocoaArray.writeToFile(plistpath, atomically: true)
, you will see it is set to False
.
To overcome this restriction, you need to
1) implement a encode function in your Person
class
func encodeWithCoder(aCoder: NSCoder!) {
aCoder.encodeObject(firstName, forKey:"firstName")
aCoder.encodeObject(lastName, forKey:"lastName")
}
2) Convert the elements in your array into NSData
, e.g.
var cocoaArray : NSArray = [NSKeyedArchiver.archivedDataWithRootObject(nateB)]
At the end, you will also need a decode function in the Person
class to support reading them back from a plist file
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With