Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS 12.0 Alternative to Using Deprecated archiveRootObject:toFile:

With iOS 12, archiveRootObject:toFile: has been deprecated. Can anyone suggest a streamlined alternative to archiving objects to a file?

//Generic example of archiver prior to iOS 12.0    
-(BOOL) archive:(id)archiveObject withFileName:(NSString*)filename
{
    NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
    return [NSKeyedArchiver archiveRootObject:archiveObject toFile:path];
}
like image 940
rswayz Avatar asked Dec 02 '18 12:12

rswayz


3 Answers

Thanks to @vadian for the hint, here's what I've come up with to do archiving and unarchiving under iOS 12:

NSError *error = nil;

NSString *docsDir;
NSArray *dirPaths;

//Get the device's data directory:
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
NSString *databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent:@"appData.data"]];

//Archive using iOS 12 compliant coding:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:@"foo" requiringSecureCoding:NO error:&error];
[data writeToFile:databasePath options:NSDataWritingAtomic error:&error];
NSLog(@"Write returned error: %@", [error localizedDescription]);

//Unarchive the data:
NSData *newData = [NSData dataWithContentsOfFile:databasePath];
NSString *fooString = [NSKeyedUnarchiver unarchivedObjectOfClass:[NSString class] fromData:newData error:&error];
like image 142
rswayz Avatar answered Nov 12 '22 08:11

rswayz


unArchivedObjectOfClass threw an error for me when trying to decode an object that didn't use secure encoding. After much trial and error, this is what finally worked without triggering an iOS 12/13 deprecation warning:

// Archive the object
NSData* data = [NSKeyedArchiver archivedDataWithRootObject:theObject requiringSecureCoding:NO error:nil];

// Unarchive the object
NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:data error:nil];
unarchiver.requiresSecureCoding = NO;
id theCopy = [unarchiver decodeTopLevelObjectForKey:NSKeyedArchiveRootObjectKey error:nil];
like image 14
Chen Lim Avatar answered Nov 12 '22 09:11

Chen Lim


As suggested by Apple, we should use FileManager for read/write the archived file.

func archiveURL() -> URL? {
    guard let documentURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first 
        else { return nil }

    return documentURL.appendingPathComponent("MyArchive.data")
}

func archive(customObject: CustomObject) {
    guard let dataToBeArchived = try? NSKeyedArchiver.archivedData(withRootObject: customObject, requiringSecureCoding: true), 
        let archiveURL = archiveURL() 
        else  {
        return
    }

    try? dataToBeArchived.write(to: archiveURL)
}

func unarchive() -> CustomObject? {
    guard let archiveURL = archiveURL(),
        let archivedData = try? Data(contentsOf: archiveURL),
        let customObject = (try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(archivedData)) as? CustomObject 
        else {
        return nil
    }

    return customObject
}
like image 11
Devo Avatar answered Nov 12 '22 09:11

Devo