0

-- a question about how to make an object that is saved to the documents directory persist on the drive and be recoverable after the iDevice is rebooted.

Here's my problem. I make a data object with NSCoding and fill it with data. I write it to the documentsDirectory each time the data in the object are updated. I stop the app and start the app again, and my data object persists, with all of its data. But if I reboot the iPhone the code I wrote to recover and read the data object fails.

The code I wrote originally used only a NSString for the file path. It worked well under ios7 but it fails under ios8.

Reading up on things, I found this clue from the Apple documentation:

"Important: Although they are safe to use while your app is running, file reference URLs are not safe to store and reuse between launches of your app because a file’s ID may change if the system is rebooted. If you want to store the location of a file persistently between launches of your app, create a bookmark as described in Locating Files Using Bookmarks."

So I rewrote my ios7 file open and file close methods so they no longer use strings or urls but get their strings and urls from a bookmark that is saved using NSUserDefaults. Same problem: everything works fine so long as I do not power off the phone, but all is lost once I do. I am not able to solve this.

Here is my current series of steps. First I either determine (or if it already exists in NSUsrDefaults, I recover) the absolute path to the documentsDirectory, using a bookmark:

 + (NSString*) getGeoModelAbsolutePath
 {
     NSString *path;
     NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
     NSURL *documentsDirectoryBookmarkURL;
     NSData* documentsDirectoryBookmark = [userDefaults objectForKey:@"documentDirectoryBookmark"];
     if(documentsDirectoryBookmark == nil)
     {
         documentsDirectoryBookmarkURL = [self getDocumentsDirectoryURL];
         documentsDirectoryBookmark = [self bookmarkForURL:documentsDirectoryBookmarkURL];
     }
     documentsDirectoryBookmarkURL = [self urlForBookmark:documentsDirectoryBookmark];
     path = documentsDirectoryBookmarkURL.path;
     path = [path stringByAppendingString:@"/Model.mod"];

     return path;
 }

using methods modified from my ios7 code (which used only the getDocumentsDirectory method):

 + (NSString *)getDocumentsDirectory
 {
     NSURL *directory = [self getDocumentsDirectoryURL];
     NSString * documentsDirectory = directory.path;
     return documentsDirectory;
 } 

And

 + (NSURL *)getDocumentsDirectoryURL
 {
      NSURL *directory = [[[NSFileManager defaultManager]
                      URLsForDirectory:NSDocumentDirectory
                      inDomains:NSUserDomainMask]
                     lastObject];
     return directory;
 }

And

 + (NSData*)bookmarkForURL:(NSURL*)url {
     NSError* theError = nil;
     NSData* bookmark = [url bookmarkDataWithOptions:NSURLBookmarkCreationSuitableForBookmarkFile
                      includingResourceValuesForKeys:nil
                                       relativeToURL:nil
                                               error:&theError];
     if (theError || (bookmark == nil)) {
         // Handle any errors.
         return nil;
     }
     return bookmark;
 }

So now I have a NSString path with the model filename that I can use to get to the GeoModel

 - (GeoModel*) openGeoModel
 {

     GeoModel *geoModel;
     NSString* documentsDirectoryGeoModel =[FileManager getGeoModelAbsolutePath];



     if([FileManager fileExistsAtAbsolutePath:documentsDirectoryGeoModel])
     {

         NSData* data = [NSData dataWithContentsOfFile: documentsDirectoryGeoModel]; //]documentsDirectoryGeoModel];
         geoModel = [NSKeyedUnarchiver unarchiveObjectWithData: data];
         NSString *unarchivedGeoModelVersion = geoModel.geoModel_VersionID;

         if(![unarchivedGeoModelVersion isEqual: currentGeoModelVersion])
         {
             [FileManager deleteFile:documentsDirectoryGeoModel];
             geoModel = [GeoModel geoModelInit];
             [Utilities setGeoProjectCounter:0];
         }

     }
     else
     {
         geoModel  = [GeoModel geoModelInit];
     }

     [FileManager saveGeoModel];
     return geoModel;

 }

Which I then can save to the documentsDirectory as follows:

 + (BOOL)saveGeoModel
 {

     NSError *error = nil;
     NSString *path = [self getGeoModelAbsolutePath];
     [NSKeyedArchiver archiveRootObject:appDelegate.currentGeoModel toFile:path];

     NSData* encodedData = [NSKeyedArchiver archivedDataWithRootObject: appDelegate.currentGeoModel];
     BOOL success = [encodedData writeToFile: path options:NSDataWritingAtomic error:&error];

  return success;  
 }

Which is always successful -- but is persistent only if I do not turn off the device! I am not making any progress with this: Any help would be much appreciated!

Thanks in advance

Tim Redfield

user1976727
  • 71
  • 10
  • Right. I don't think this qualifies as answering my own question -- because the error I committed was not in this code. (I was not saving the data in the correct order: – user1976727 Jan 23 '15 at 19:12
  • (continued) -- I saved prematurely, so there was nothing in the data object: what was unarchived was nil. – user1976727 Jan 23 '15 at 19:13
  • (sorry -- keyboard is sensitive). My point: The above code actually works quite well, and is persistent -- so long as you write a data object to the documentDirectory in the correct sequence such that it has data in it, and is not nil. In the above example, my local instance of geoModel had data but because I saved it prematurely, what the rest of my app saw was an object that did not exist. – user1976727 Jan 23 '15 at 19:17
  • And one more point for anybody looking for a similar answer: A much shorter method could be – user1976727 Jan 23 '15 at 19:17
  • NSData* encodedData = [NSKeyedArchiver archivedDataWithRootObject: geoModell]; NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; [userDefaults setObject:encodedData forKey:@"archivedGeoModel"]; [ userDefaults synchronize]; – user1976727 Jan 23 '15 at 19:19

1 Answers1

0

There. I think it is answered -- unless someone else has a comment on how to improve the above listings, they DO work as they ought to!

user1976727
  • 71
  • 10