简体   繁体   中英

What is the correct way to unarchive something that was archived using encodeRootObject:?

I am attempting to use the Keyed Archiver classes for the first time and I'm failing the last assert in this simple test (OCUnit):

- (void) testNSCoding
{
    NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:5];
    [dict setObject:@"hello" forKey:@"testKey"];

    NSMutableData* data = [NSMutableData data];
    NSKeyedArchiver *ba = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
    [ba encodeRootObject:dict];
    [ba finishEncoding];

    STAssertTrue(data.length != 0, @"Archiver gave us nothing.");

    NSKeyedUnarchiver *bua = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
    id decodedEntity = [bua decodeObjectForKey:@"root"];
    [bua finishDecoding];
    STAssertNotNil(decodedEntity, @"Unarchiver gave us nothing.");
}

I have confirmed that the archiver is archiving, I'm assuming the issue exists in the unarchiving. According to the Archives and Serializations Guide I believe that perhaps there is some issue with how I am using the Unarchiver?

Thanks!

First, you should not use the encodeRootObject method. That's a legacy method defined in NSCoder to support obsolete non-keyed archivers, and can only be decoded using decodeObject: . You only use the pair of encodeObjectForKey: and decodeObjectForKey: .

So,

 id decodedEntity = [bua decodeObjectForKey:@"root"];

should be

 id decodedEntity = [bua decodeObjectForKey:@"testKey"];

If you want to decode the totality of a dictionary, instead of

[ba encodeRootObject:dict];

do

[ba encodeObject:dict forKey:@"root"];

By the way, for simple purposes it often suffices to use NSUserDefaults , which automatically takes care of creating the file to write on, writing things on the file, and reading it when the program is launched the next time.

If you just need to encode a dictionary, using NSPropertyListSerialization usually suffices.

If you do use NSKeyedArchiver and NSKeyedUnarchiver , I recommend you to follow the practice and write encodeWithCoder: and initWithCoder: for an object.

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    id profileData = [defaults dataForKey:kProfileDataKey]; // or you can get it from the web
    if (profileData && [profileData isKindOfClass:[NSData class]]) {
        NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:(NSData *)profileData];
        unarchiver.requiresSecureCoding = YES; // <NSSecureCoding>
        id object = [unarchiver decodeObjectOfClass:[MyClass class] forKey:NSKeyedArchiveRootObjectKey];
        NSLog(@"%@", object);
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM