Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS Swift: saving an array of custom classes

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.

like image 599
Nate Birkholz Avatar asked Aug 16 '14 23:08

Nate Birkholz


2 Answers

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
}
like image 125
Kaiyuan Xu Avatar answered Oct 24 '22 11:10

Kaiyuan Xu


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

like image 35
Anthony Kong Avatar answered Oct 24 '22 11:10

Anthony Kong