1

I am trying to save a simple array of objects in the persistent memory by executing the following code:

let fileManager=NSFileManager()
     let urls = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)

     if urls.count>0{

         let localDocumentsDirectory=urls[0]
         let archivePath=localDocumentsDirectory.URLByAppendingPathExtension("meditations.archive")
         NSKeyedArchiver.archiveRootObject(self.meditationsArray, toFile: archivePath.path!)
         let restored=NSKeyedUnarchiver.unarchiveObjectWithFile(archivePath.path!)

         print("restored \(restored)")
     }
}

Yet, when I print the restored date as in the code I find nil.
Conversely, if I use the CachesDirectory the array is soon after restored fine,
but when I reopen the app and try to load the data, it is lost. What is correct way to persistently save data?

boraseoksoon
  • 2,164
  • 1
  • 20
  • 25
Fabrizio Bartolomucci
  • 4,948
  • 8
  • 43
  • 75

2 Answers2

0

I think the problem is that your are using URLByAppendingPathExtension, when you should be using URLByAppendingPathComponent. The "path extension" is the file extension, so your archivePath is "~/Documents.meditations.archive". It might be temporarily working with the CachesDirectory, because it's putting the data into a temporary file somewhere, or maybe just reading it back from memory. This should fix it:

let fileManager = NSFileManager()
let documentDirectoryUrls = fileManager.URLsForDirectory(.DocumentDirectory, .UserDomainMask)

if let documentDirectoryUrl = documentDirectoryUrls.first {
    let fileUrl = documentDirectoryUrl.URLByAppendingPathComponent("meditations.archive")

    // Also, take advantage of archiveRootObject's return value to check if
    // the file was saved successfully, and safely unwrap the `path` property
    // of the URL. That will help you catch any errors.
    if let path = fileUrl.path {
        let success = NSKeyedArchiver.archiveRootObject(meditationArray, toFile: path)

        if !success {
            print("Unable to save array to \(path)")
        }
    } else {
        print("Invalid path")
    }
} else {
    print("Unable to find DocumentDirectory for the specified domain mask.")
}
ConfusedByCode
  • 1,137
  • 8
  • 27
0

I faced the same issue, I was unable to archive and unarchive array of objects using NSKeyedArchiver, I think the issue is that I'm using the below method :

NSKeyedArchiver.archiveRootObject(arrayOfItems, toFile: FileManager.getFileURL("My-File-Name")!)

I think this method is for archiving Objects, not array of Objects.

Anyway, I found a solution to my problem, by wrapping the whole array in an object, check below :

let myArrayItemsContainer = ArrayItemsContainer()
myArrayItemsContainer.allItems = arrayOfItems
NSKeyedArchiver.archiveRootObject(myArrayItemsContainer, toFile: FileManager.getFileURL("My-File-Name")!)

and I used the below code to unarchive my object :

NSKeyedUnarchiver.unarchiveObject(withFile: FileManager.getFileURL("My-File-Name")!) as? ArrayItemsContainer

Also I used this extension for using FileManager.getFileURL

public extension FileManager {
     /// Returns the URL of the file given a name
     ///
     /// - Parameter fileName: The file name of the file + extension
     /// - Returns: The URL as String
     static func getFileURL(_ fileName: String) -> String? {
     let fileURL = FileManager().urls(for: FileManager.SearchPathDirectory.documentDirectory, in: FileManager.SearchPathDomainMask.userDomainMask).first
         return (fileURL?.appendingPathComponent(fileName).path)
     }
}
MhmdRizk
  • 1,591
  • 2
  • 18
  • 34