Archiving / Unarchiving results in initForReadingWithData incomprehensible archive
Asked Answered
M

3

5

I've implemented an save on applicationWillTerminate and load on applicationWillFinishLoading. There is a complete object tree, all implement the NSCoding protocol and I've check the types I enter.

One of the classes also stores an NSMutableData to the NSKeyedArchive, which I suspect might break unarchiving occasionally. Weirdly enough, sometimes it works and sometimes it doesn't. I suspect some content in the NSMutableData will break the archiving.

I use encodeObject on all objects, except for the bools and int where I use the correct corresponding method (encodeBool:forKey: and encodeInt:forKey:)

To be more clear: the code really does work, sometimes is it able to rebuild a rather complete object graph, just not all the time.

The error message I get is:

initForReadingWithData incomprehensible archive 0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30

Added: code which is failing, it an NSMutableData of 10+ MB

- (void)encodeWithCoder:(NSCoder*)encoder {
[encoder encodeObject:self.encodedMessage forKey:@"EncodedMessage"]; //NSData
[encoder encodeObject:self.data forKey:@"Data"]; //NSMutableData (10+MB)
[encoder encodeObject:self.header forKey:@"Header"]; //NSString
[encoder encodeObject:self.fileName forKey:@"FileName"]; //NSString
[encoder encodeInt:self.dataStartIndex forKey:@"DataStartIndex"]; //int
[encoder encodeInt:self.dataEndIndex forKey:@"DataEndIndex"]; //int
}

- (id)initWithCoder:(NSCoder*)decoder {
    if (self = [super init]) {
        self.encodedMessage = [decoder decodeObjectForKey:@"EncodedMessage"]; //NSData
        self.data = [decoder decodeObjectForKey:@"Data"]; //NSMutableData
        self.header = [decoder decodeObjectForKey:@"Header"]; //NSString
        self.fileName = [decoder decodeObjectForKey:@"FileName"]; //NSString
        self.dataStartIndex = [decoder decodeIntForKey:@"DataStartIndex"]; //int
        self.dataEndIndex = [decoder decodeIntForKey:@"DataEndIndex"]; //int
    }

    return self;
}

When I remove the self.data encoding and decoding it always seem to work. It also fails with smaller sized self.data. Doesn't seem size but content issue?

Tried to open the file when I did write the nsmutabledata to it, the propertly list editor displays the error:

"Conversion of string failed. The string is empty."

plutil also gives this error:

"$ plutil -lint nzbvortex.state nzbvortex.state: Conversion of string failed. The string is empty."
Madcap answered 8/1, 2010 at 9:53 Comment(1)
I have encountered this problem, too. The error message is exactly the same as yours. I use NSKeyedUnarchiver in a NSFileCoordinator reading block to unarchive data that is archived by NSKeyedArchiver in another thread. The crash happens occasionally and I cannot reproduce it when debugging. Have you got a solution?Nathan
M
2

It seems that store more than around 230000 bytes via an NSMutableArray will cause the NSKeyedArchiver to create a broken plist file.

220000 works, 250000 didn't. Did search for the exact amount that is allowed.

Madcap answered 8/1, 2010 at 21:24 Comment(1)
It's because of the binary plist being trucated.Spickandspan
P
5

FWIW I have also come across this problem and here is what I've found.

The bytes reported 0x62, 0x70, 0x6c, etc., are part of the magic string "bplist" at the start of a binary property list, which NSKeyedArchiver uses by default.

A binary property list stores metadata in a trailer (i.e. at the end of the data). So if it gets truncated, the entire plist becomes unreadable.

If you want to check whether that's what has happened to you, you can use NSPropertyListReader_binary1 from Cocotron (http://code.google.com/p/cocotron/source/browse/Foundation/NSPropertyList/) to see how the file format works.

Hope this helps someone!

Pecan answered 8/1, 2010 at 9:53 Comment(1)
The exact error for me was the data getting trucated, like you said. Your answer should be marked right. Thanks.Spickandspan
M
2

It seems that store more than around 230000 bytes via an NSMutableArray will cause the NSKeyedArchiver to create a broken plist file.

220000 works, 250000 didn't. Did search for the exact amount that is allowed.

Madcap answered 8/1, 2010 at 21:24 Comment(1)
It's because of the binary plist being trucated.Spickandspan
G
0

For the bool and int, there are two methods: encodeBool:forKey: and encodeInt:forKey: (taken from the NSKeyedArchiver reference).

For the NSMutableData, you should archive them with encodeObjectForKey: and unarchive them with decodeObjectForKey:.

You can refer to this useful guide for more cases.

Gilbertgilberta answered 8/1, 2010 at 10:10 Comment(3)
That is exactly what I do. The code works, but not always. It looks like specific contents seems to break the encoding.Madcap
Are you using the XML Property List format ? If so, have you tried to open the archive with the PList editor (in Developer Tools) ?Gilbertgilberta
It seems there is an limit on the amount of bytes to be stored in an nsmutabledata when using an NSKeyedArchiver. Problem solved (bypassed actually). Thanks for helping.Madcap

© 2022 - 2024 — McMap. All rights reserved.