1

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!

Chris Hill
  • 1,914
  • 1
  • 16
  • 24

2 Answers2

1

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.

Yuji
  • 34,103
  • 3
  • 70
  • 88
  • Sorry, that doesn't pass, I am not trying to get the string "hello", I'm trying to get the dictionary. To answer your question the bottom of the above linked page says: If you want to customize the unarchiving process for an archive previously created using archiveRootObject:toFile:, you can use decodeObjectForKey: and the key “root” to identify the root object in the archive. – Chris Hill May 09 '11 at 04:49
  • Thanks for the tip on NSUserDefaults. This test is for a much more complicated pickling subsystem that I'm writing, tho. NSUserDefaults would not suffice. – Chris Hill May 09 '11 at 04:50
  • Well, but you didn't use `archiveRootObject:toFile:`, did you? – Yuji May 09 '11 at 04:58
  • Correct! So I guess the question I'm asking is: what is the correct way to unarchive something that was archived using encodeRootObject:? – Chris Hill May 09 '11 at 05:48
  • Edit: Didn't notice you modified the above part of your answer. Not using encodeRootObject is interesting news for me, thanks! I will attempt your suggestions. I did not want to use encodeObject because it looked as though the documentation was saying that encodeRootObject: was the way to encode objects if I wanted to get correct references injected. Its late, will pick this up in the morning, thanks again. – Chris Hill May 09 '11 at 06:00
  • You read the wrong place in the documentation. You should completely forget the non-keyed archives, and only should use keyed archives. Apple should delete those sections on non-keyed archives. Those were for pre-10.2 systems! Jeez. – Yuji May 09 '11 at 06:15
0
    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);
    }
Dmitrii Cooler
  • 4,032
  • 1
  • 22
  • 21