NSKeyedUnarchiver 发现损坏的数据

NSKeyedUnarchiver finds corrupted data

我有一个存档程序和一个解档程序可以协同工作。

第二个程序的运行结果表明,尽管两个对象(myFoo1)中的一个对象(myFoo1)已很好地归档、存储并稍后取消归档,但另一个(myBook)似乎无法正确取消归档。我只是不知道在似乎损坏了部分原始数据的归档 and/or 解档过程中发生了什么。我已仔细确保编码密钥与解码密钥相同,但程序仍然存在。

归档程序代码:

#import <Foundation/Foundation.h>

@interface Foo : NSObject <NSCoding>

@property (copy, nonatomic) NSString * strVal;
@property int intVal;
@property float floatVal;

-(void) display;

@end

#import "Foo.h"

@implementation Foo

@synthesize  strVal, intVal, floatVal;

-(void) encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeObject: strVal forKey: @"FoostrVal"];
    [aCoder encodeInt: intVal forKey: @"FoointVal"];
    [aCoder encodeFloat: floatVal forKey: @"FoofloatVal"];
    // NSLog (@"Foo encodeWithCoder called"); called
}

-(id) initWithCoder:(NSCoder *)aDecoder
{
    strVal = [aDecoder decodeObjectForKey: @"FoostrVal"];
    intVal = [aDecoder decodeIntForKey: @"FoointVal"];
    floatVal = [aDecoder decodeFloatForKey: @"FoofloatVal"];
    // NSLog (@"Foo initWithCoder called"); not called
    return self;
}

-(void) display
{
    NSLog (@"%@ %i %g", strVal, intVal, floatVal);
}

@end

#import <Foundation/Foundation.h>

@interface AddressCard : NSObject <NSCoding>

@property (nonatomic, copy) NSString * name, * email;

-(instancetype) initWithName: (NSString *) theName andEmail: (NSString *) theEmail;
-(void) showCard;

@end

#import "AddressCard.h"

@implementation AddressCard

@synthesize name, email;

-(instancetype) initWithName: (NSString *) theName andEmail: (NSString *) theEmail
{
    self = [super init];
    if (self) {
        self.name = [NSString stringWithString: theName];
        self.email = [NSString stringWithString: theEmail];
    }
    return self;
}

-(instancetype) init
{
    return [self initWithName: @"NoName" andEmail: @"NoEmail"];
}

-(void) encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeObject: name forKey: @"AddrCardName"];
    [aCoder encodeObject: email forKey: @"AddrCardEmail"];
    // NSLog (@"AddressCard encodeWithCoder called"); called
}

-(id) initWithCoder:(NSCoder *)aDecoder
{
    [aDecoder decodeObjectForKey: @"AddrCardName"];
    [aDecoder decodeObjectForKey: @"AddrCardEmail"];
    // NSLog (@"AddressCard initWithCoder called"); not called

    return self;
}

-(void) showCard
{
    NSLog (@"%-20s%-40s", [name UTF8String], [email UTF8String]);
}

@end

#import "AddressCard.h"

@interface AddressBook : NSObject <NSCoding>

@property (nonatomic, copy) NSString * title;
@property (nonatomic, strong) NSMutableArray * book;

-(instancetype) initWithTitle: (NSString *) title;
-(void) addCard: (AddressCard *) card;
-(void) list;

@end

#import "AddressBook.h"

@implementation AddressBook

@synthesize title, book;

-(instancetype) initWithTitle: (NSString *) theTitle
{
    self = [super init];
    if (self) {
        title = [NSString stringWithString: theTitle];
        book = [NSMutableArray array];
    }
    return self;
}

-(instancetype) init
{
    return [self initWithTitle: @"NoTitle"];
}

-(void) encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeObject: title forKey: @"AddrBookTitle"];
    [aCoder encodeObject: book forKey: @"AddrBookBook"];
    // NSLog (@"AddressBook encodeWithCoder called"); called
}

-(id) initWithCoder:(NSCoder *)aDecoder
{
    [aDecoder decodeObjectForKey: @"AddrBookTitle"];
    [aDecoder decodeObjectForKey: @"AddrBookBook"];
    // NSLog (@"AddressBook initWithCoder called"); not called

    return self;
}

-(void) addCard: (AddressCard *) card
{
    if ([book containsObject: card] == YES)
        NSLog (@"The card already exists in %@", title);
    else
        [book addObject: card];
}

-(void) list
{
    for (AddressCard * card in book)
        [card showCard];
}

@end

#import "AddressBook.h"
#import "Foo.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Foo * myFoo1 = [[Foo alloc] init];
        NSMutableData * dataArea;
        NSKeyedArchiver * archiver;
        AddressBook * myBook = [[AddressBook alloc] initWithTitle: @"Steve's Address Book"];

        NSString * aName = @"Julia Kochan";
        NSString * aEmail = @"jewls337@axlc.com";
        NSString * bName = @"Tony Iannino";
        NSString * bEmail = @"tony.iannino@tecfitness.com";
        NSString * cName = @"Stephen Kochan";
        NSString * cEmail = @"steve@steve_kochan.com";
        NSString * dName = @"Jamie Baker";
        NSString * dEmail = @"jbaker@hitmail.com";
        NSString * filePath = @"addrbook.arch";

        AddressCard * card1 = [[AddressCard alloc] initWithName: aName andEmail: aEmail];
        AddressCard * card2 = [[AddressCard alloc] initWithName: bName andEmail: bEmail];
        AddressCard * card3 = [[AddressCard alloc] initWithName: cName andEmail: cEmail];
        AddressCard * card4 = [[AddressCard alloc] initWithName: dName andEmail: dEmail];

        // Add some cards to the address book
        [myBook addCard: card1];
        [myBook addCard: card2];
        [myBook addCard: card3];
        [myBook addCard: card4];

        myFoo1.strVal = @"This is the string";
        myFoo1.intVal = 12345;
        myFoo1.floatVal = 99.8;

        // Set up a data area and connect it to an NSKeyedArchiver object
        dataArea = [NSMutableData data];
        archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData: dataArea];

        // Now we can begin to archive objects
        [archiver encodeObject: myBook forKey: @"myaddrbook"];
        [archiver encodeObject: myFoo1 forKey: @"myfoo1"];
        [archiver finishEncoding];

        // Write the archived data area to a file
        if ([dataArea writeToFile: filePath atomically: YES] == NO)
            NSLog (@"Archiving failed!");
        NSLog (@"All operations successful!");

    }
    return 0;
}

解压程序代码:

#import <Foundation/Foundation.h>

@interface Foo : NSObject <NSCoding>

@property (copy, nonatomic) NSString * strVal;
@property int intVal;
@property float floatVal;

-(void) display;

@end

#import "Foo.h"

@implementation Foo

@synthesize  strVal, intVal, floatVal;

-(void) encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeObject: strVal forKey: @"FoostrVal"];
    [aCoder encodeInt: intVal forKey: @"FoointVal"];
    [aCoder encodeFloat: floatVal forKey: @"FoofloatVal"];
    // NSLog (@"Foo encodeWithCoder called"); not called
}

-(id) initWithCoder:(NSCoder *)aDecoder
{
    strVal = [aDecoder decodeObjectForKey: @"FoostrVal"];
    intVal = [aDecoder decodeIntForKey: @"FoointVal"];
    floatVal = [aDecoder decodeFloatForKey: @"FoofloatVal"];
    // NSLog (@"Foo initWithCoder called"); called

    return self;
}

-(void) display
{
    NSLog (@"%@\n%i\n%g", strVal, intVal, floatVal);
}

@end

#import <Foundation/Foundation.h>

@interface AddressCard : NSObject <NSCoding>

@property (nonatomic, copy) NSString * name, * email;

-(instancetype) initWithName: (NSString *) theName andEmail: (NSString *) theEmail;
-(void) showCard;

@end

#import "AddressCard.h"

@implementation AddressCard

@synthesize name, email;

-(instancetype) initWithName: (NSString *) theName andEmail: (NSString *) theEmail
{
    self = [super init];
    if (self) {
        self.name = [NSString stringWithString: theName];
        self.email = [NSString stringWithString: theEmail];
    }
    return self;
}

-(instancetype) init
{
    return [self initWithName: @"NoName" andEmail: @"NoEmail"];
}

-(void) encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeObject: name forKey: @"AddrCardName"];
    [aCoder encodeObject: email forKey: @"AddrCardEmail"];
    // NSLog (@"AddressCard encodeWithCoder called"); not called
}

-(id) initWithCoder:(NSCoder *)aDecoder
{
    [aDecoder decodeObjectForKey: @"AddrCardName"];
    [aDecoder decodeObjectForKey: @"AddrCardEmail"];
    // NSLog (@"AddressCard initWithCoder called"); called

    return self;
}

-(void) showCard
{
    NSLog (@"%-20s%-40s", [name UTF8String], [email UTF8String]);
}

@end

#import "AddressCard.h"

@interface AddressBook : NSObject <NSCoding>

@property (nonatomic, copy) NSString * title;
@property (nonatomic, strong) NSMutableArray * book;

-(instancetype) initWithTitle: (NSString *) title;
-(void) addCard: (AddressCard *) card;
-(void) list;

@end

#import "AddressBook.h"

@implementation AddressBook

@synthesize title, book;

-(instancetype) initWithTitle: (NSString *) theTitle
{
    self = [super init];
    if (self) {
        title = [NSString stringWithString: theTitle];
        book = [NSMutableArray array];
    }
    return self;
}

-(void) encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeObject: title forKey: @"AddrBookTitle"];
    [aCoder encodeObject: book forKey: @"AddrBookBook"];
    // NSLog (@"AddressBook encodeWithCoder called"); not called

}

-(id) initWithCoder:(NSCoder *)aDecoder
{
    [aDecoder decodeObjectForKey: @"AddrBookTitle"];
    [aDecoder decodeObjectForKey: @"AddrBookBook"];
    // NSLog (@"AddressBook initWithCoder called"); called

    return self;
}

-(void) addCard: (AddressCard *) card
{
    if ([book containsObject: card] == YES)
        NSLog (@"The card already exists in %@", title);
    else
        [book addObject: card];
}

-(void) list
{
    for (AddressCard * card in book)
        [card showCard];
}

@end

#import "AddressBook.h"
#import "Foo.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSData * dataArea;
        NSKeyedUnarchiver * unarchiver;
        Foo * myFoo1;
        AddressBook * myBook;
        NSString * filePath = @"addrbook.arch";

        // Read in the archive and connect an
        // NSkeyedUnarchiver object to it

        dataArea = [NSData dataWithContentsOfFile: filePath];
        if (!dataArea) {
            NSLog (@"Can't read back archive file!");
            return 1;
        }
        unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData: dataArea];
        // Decode the objects we previously stored in the archive
        myBook = [unarchiver decodeObjectForKey: @"myaddrbook"];
        myFoo1 = [unarchiver decodeObjectForKey: @"myfoo1"];
        [unarchiver finishDecoding];

        // Verify that the resote was successful
        if (myBook != nil) {
            if ([myBook.book count] == 0)
                NSLog (@"Data corrupted in myBook!");
            else
                [myBook list];
        }
        else
            NSLog (@"Load myBook failed!");

        if (myFoo1 != nil)
            [myFoo1 display];
        else
            NSLog (@"Load myFoo1 failed!");
    }
    return 0;
}

运行 以上解档程序的结果: myBook 中的数据已损坏! 这是字符串 12345 99.8 程序以退出代码结束:0

这里有两个问题:您的 AddressBookAddressCard -initWithCoder: 实现都不是

  1. 呼叫self = [super init]。这不是问题的根本原因,但肯定是不正确的
  2. 也不会将解码结果分配给您的任何属性。您解码 AddrBookBook,但永远不会将其分配给 self.book;因此,myBook.book == nil[myBook.book count] == 0。所有解码调用都应显示为 myIvar = [aDecoder decodeObjectForKey:...]