我正在使用NSURLConnection从服务器获取XML数据。我正在解析数据并在tableview中显示它。这一切都按预期工作。现在,我想保存下载的数据以供离线使用。我们的想法是下载NSData,将其转换为NSArray并将其存储到NSUserDefaults或单独的文件中。但是,我在将NSData转换为NSArray时遇到问题。
我在(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
方法中添加了逻辑。我想做的是如下:
NSError *error;
NSPropertyListFormat plistFormat;
id object = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListImmutable format:&plistFormat error:&error];
if (error != nil) {
NSLog(@"Error %@", [error localizedDescription]);
[error release];
}
if ([object isKindOfClass:[NSArray class]]) {
NSLog(@"IS Array");
NSArray *objectArray = object;
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:objectArray] forKey:@"myKey"];
} else {
NSLog(@"Not an array");
}
在日志中我得到如下:
错误无法完成操作。 (可可错误3840.)
不是数组
如果我删除错误处理并留下线
NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithData:data];
我的应用程序崩溃时出现以下消息:`
因未捕获的异常'NSInvalidArgumentException'而终止应用程序,原因:'*** - [NSKeyedUnarchiver initForReadingWithData:]:难以理解的存档(0x3c,0x3f,0x78,0x6d,0x6c,0x20,0x76,0x65)'
为什么会这样?什么是Cocoa错误3840?
我的对象实现了NSCoding协议,并且有encodeWithCoder
和initWithCoder
方法。我的对象的每个属性都必须编码/解码吗?
编辑:这是我的对象: Currency.h
@interface Currency : NSObject<NSCoding>{
CGFloat value;
NSString *code;
NSDate *date;
NSString *description;
NSString *imagePath;
}
@property (nonatomic, assign) CGFloat value;
@property (nonatomic, retain) NSString *code;
@property (nonatomic, retain) NSDate *date;
@property (nonatomic, retain) NSString *description;
@property (nonatomic, retain) NSString *imagePath;
Currency.m
@implementation Currency
@synthesize value;
@synthesize code;
@synthesize date;
@synthesize description;
@synthesize imagePath;
static NSString * const keyCode = @"code";
static NSString * const keyDescription = @"description";
static NSString * const keyValue = @"value";
- (void)dealloc {
[code release];
[date release];
[description release];
[imagePath release];
[super dealloc];
}
- (void)encodeWithCoder:(NSCoder *)coder
{
if ([coder allowsKeyedCoding]) {
[coder encodeObject:code forKey: keyCode];
[coder encodeObject:description forKey: keyDescription];
[coder encodeFloat:value forKey: keyValue];
}
}
}
- (id)initWithCoder:(NSCoder *) coder {
self = [[Currency alloc] init];
if (self != nil)
{
code = [[coder decodeObjectForKey:keyCode] retain];
description = [[coder decodeObjectForKey:keyDescription] retain];
value = [coder decodeFloatForKey:keyValue];
}
return self;
}
@end
修改回答:
因此,这里有三个不同的概念:通用XML,propertyLists(二进制或XML格式)和Archive。您使用NSXMLParser或其他库解析XML以转换为Obj-C对象。您可以将核心Obj-C对象(不包括您的自定义类货币)保存到属性列表中并将其读回。或者,您可以将任何对象/对象图(使用编码器)存档到存档中,并使用NSKeyedUnarchiver将其读回。
即使它们下面可能共享实现,也不能混合它们。例如,首先您尝试将XML作为propertyList读取,即使pLists是XML,您的通用CurrencyData XML也没有正确的plist格式(例如,否)。另外,即使你要写一个plist,你也必须将Currency转换为NSDictionary才能使它在plist中存储,这意味着你不需要编码器。
然后,您尝试使用NSKeyedUnarchiver读取XML并获得消息“难以理解的存档”。同样正确,因为它不是用NSKeyedArchive创建的。
因此,您无法使用原始流并直接在您的对象中删除或取消归档。但是要保存解析后的XMLArray以供离线使用,您可以将Currency转换为NSDictionary并使用属性列表,或者只是保持原样,并使用NSKeyedArchive和Unarchive这样(利用您提供的编码器/解码器):
//To save
NSData * data = [NSKeyedArchiver archivedDataWithRootObject:xmlArray];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"myKey"]; //or store in another file
//To later read
NSData * data2 = [[NSUserDefaults standardUserDefaults] valueForKey:@"myKey"];
NSArray * newXMLArray = [NSKeyedUnarchiver unarchiveObjectWithData:data2];
希望能搞清楚。调查它也清除了我自己对何时使用哪种技术的理解。
//原始评论:如果您已将传入数据解析为tableView的模型,为什么不序列化该数据副本而不是原始流?
您是否有理由不直接将NSData对象保存到文件中
data writeToFile:(NSString*)path atomically:(BOOL)flag
?
我认为你的NSPropertyList调用没有错误 - 如果发生错误,propertyListWithData函数返回nil,我认为错误只有在那时才有效。你可能应该检查返回值!= nil,然后打印错误。错误3840表示属性列表错误范围的开始,它本身看起来不像错误。
propertyListWithData的描述也说它返回一个属性列表,而不是一个数组,所以isKindOfClass说它不是一个数组就不足为奇了......看到这里: