我在NSUserDefaults中添加了类别方法来存储和检索编码对象(在本例中为NSArray)。我在检索编码数据时遇到问题。这是我的代码:
- (void)encodeObject:(id<NSCoding>)object forKey:(NSString *)key {
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:object requiringSecureCoding:NO error:nil];
[self setObject:data forKey:key];
[self synchronize];
}
- (id)decodeObjectForKey:(NSString *)key class:(Class)aClass {
NSData *data = [self objectForKey:key];
NSError *error = nil;
id object = [NSKeyedUnarchiver unarchivedObjectOfClass:aClass fromData:data error:&error];
NSLog(@"E: %@ %@", error.localizedDescription, object);
return object;
}
调用[[NSUserDefaults standardDefaults] encodeObject:object forKey:key]
应该对传递的对象进行编码并将其存储为默认值,然后调用[[NSUserDefaults standardDefaults] decodeObjectForKey:key class:aClass
应该返回已编码的对象。
问题是[NSKeyedUnarchiver unarchivedObjectOfClass:fromData:error:]
返回nil
,并且错误文本记录为The data couldn’t be read because it isn’t in the correct format.
。使用[self objectForKey:]
检索的数据为__NSCFData
类型。我不知道这是否相关,因为AFAIK __NSCFData是免费电话桥接到NSData。
用[NSKeyedUnarchiver unarchivedObjectOfClass:fromData:error:]
代替[NSKeyedUnarchiver unarchiveObjectWithData:]
解决了这个问题。数据已正确存储和检索。但是现在不赞成使用此方法,因此我需要转到更现代的方法,但无法确定为什么它不起作用。
答案 0 :(得分:2)
我有一个类似的问题。我发现我必须传递NSArray中对象的类。
NSSet *set = [NSSet setWithArray:@[
[NSArray class],
[STUFF_IN_ARRAY class]
]];
NSArray *results = [NSKeyedUnarchiver unarchivedObjectOfClasses:set fromData: rawData error: &error];
答案 1 :(得分:2)
对于自定义类,其他答案都没有足够涵盖(或者说得足够清楚),因此希望我可以通过添加答案来帮助某些人!
如果数据代表具有各种类属性的自定义类的存档数组,则仅提供数组类和自定义类是不够的,您需要提供自定义类用于的所有类,例如:
NSData* data;
NSError* error;
[NSKeyedUnarchiver unarchivedObjectOfClasses:
[NSSet setWithArray: @[
[NSMutableArray class],
[CustomClass class],
// CustomClass has properties using the following classes:
[NSDate class],
[NSString class],
[NSNumber class],
[NSIndexSet class]
]]
fromData: data
error: &error];
答案 2 :(得分:1)
为了获得灵感,我正在解决通过[NSKeyedUnarchiver unarchivedObjectOfClasses:fromData:]从文件取消存档数据的方法。 改进很小:您不需要在方法调用中列出所有类,因为最常用的类会自动添加到方法主体中。
// MyFileManager.m
- (id)getDataFromFile:(NSString *)file inSubfolder:(NSString *)subfolder dataClasses:(NSArray<Class> *)classes {
NSString *filePath = [self pathForFile:file subfolder:subfolder];
NSData *data = [[NSFileManager defaultManager] contentsAtPath:filePath];
NSArray *extendedClasses = [classes arrayByAddingObjectsFromArray:@[[NSArray class], [NSMutableArray class], [NSDictionary class], [NSMutableDictionary class], [NSDate class], [NSNumber class]]];
NSError *unarchivingError;
id unarchived = [NSKeyedUnarchiver unarchivedObjectOfClasses:[NSSet setWithArray:extendedClasses] fromData:data error:&unarchivingError];
if (unarchivingError) {
return nil;
} else {
return unarchived;
}
}
这是该方法的用法 //预期的未归档数据在字典中
NSDictionary *dictionary = [FILE_MANAGER getDataFromFile:@"testfile" inSubfolder:nil dataClasses:@[[MyClass class]]];
还有一个小建议。您的“ MyClass”必须符合“ NSSecureCoding”协议。并在您的“ MyClass”中实现3种方法...
@interface MyClass : NSObject <NSSecureCoding> // MyClass.h
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) NSDate *date;
@property (nonatomic) NSInteger count;
@end
@implementation MyClass // MyClass.m
- (id)initWithCoder:(NSCoder *)decoder {
if (self = [super init]) {
self.name = [decoder decodeObjectOfClass:[NSString class] forKey:@"name"];
self.date = [decoder decodeObjectOfClass:[NSDate class] forKey:@"date"];
self.count = [decoder decodeIntegerForKey:@"count"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.name forKey:@"name"];
[encoder encodeObject:self.date forKey:@"date"];
[encoder encodeInteger:self.count forKey:@"count"];
}
+ (BOOL)supportsSecureCoding{
return YES;
}
对于那些希望查看帮助方法“ pathForFile”的人-我将其用作主要的“库/应用程序支持”(因为本文表1-3 :iOS File System Basics )
// MyFileManager.m
- (NSString *)pathForFile:(NSString *)file subfolder:(NSString *)subfolder {
NSString *folderPath = [self storageFolderPathWithSubfolder:subfolder];
NSString *filePath = [folderPath stringByAppendingPathComponent:file];
return filePath;
}
- (NSString *)storageFolderPathWithSubfolder:(NSString *)subfolder {
NSString *storageFolderPath = [self storageFolderPath];
if (!subfolder.length) {
return storageFolderPath;
}
NSString *subfolderPath = [storageFolderPath stringByAppendingPathComponent:subfolder];
if (![[NSFileManager defaultManager] fileExistsAtPath:subfolderPath]) { //Does directory already exist?
[[NSFileManager defaultManager] createDirectoryAtPath:subfolderPath withIntermediateDirectories:NO attributes:@{ NSFileProtectionKey: NSFileProtectionNone } error:nil];
}
return subfolderPath;
}
- (NSString *)storageFolderPath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *storageFolderPath = [paths firstObject];
// create folder if it doesn't exist
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL folderExists = [fileManager fileExistsAtPath:storageFolderPath];
if (!folderExists) {
[fileManager createDirectoryAtPath:storageFolderPath withIntermediateDirectories:NO attributes:@{ NSFileProtectionKey: NSFileProtectionNone } error:nil];
}
return storageFolderPath;
}
答案 3 :(得分:-1)
此行应为您工作:
[NSKeyedUnarchiver unarchivedObjectOfClass:NSArray.class fromData:data error:&err];