mas*_*ers 4 nscoding nskeyedarchiver ios nskeyedunarchiver
我已将类别方法添加到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;
}
Run Code Online (Sandbox Code Playgroud)
调用[[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:]
可解决问题。数据已正确存储和检索。但是现在不赞成使用此方法,因此我需要转到更现代的方法,但无法确定为什么它不起作用。
对于自定义类(或使其足够清晰),其他答案都没有足够好地涵盖这一点,因此希望我可以通过添加答案来帮助某些人!
如果您的数据表示具有各种类属性的自定义类的存档数组,那么仅提供数组类和自定义类是不够的,您需要提供自定义类使用的所有类,例如:
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];
Run Code Online (Sandbox Code Playgroud)
我有一个类似的问题。我发现我必须传递NSArray中对象的类。
NSSet *set = [NSSet setWithArray:@[
[NSArray class],
[STUFF_IN_ARRAY class]
]];
NSArray *results = [NSKeyedUnarchiver unarchivedObjectOfClasses:set fromData: rawData error: &error];
Run Code Online (Sandbox Code Playgroud)
为了获得灵感,我正在通过 [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;
}
}
Run Code Online (Sandbox Code Playgroud)
这是该方法的用法 // 预期的未归档数据在字典中
NSDictionary *dictionary = [FILE_MANAGER getDataFromFile:@"testfile" inSubfolder:nil dataClasses:@[[MyClass class]]];
Run Code Online (Sandbox Code Playgroud)
还有一个小建议。您的“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;
}
Run Code Online (Sandbox Code Playgroud)
对于那些想要查看帮助方法“pathForFile”的人 - 我使用“Library/Application Support”作为主要内容(因为本文表 1-3:iOS 文件系统基础知识)
// 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;
}
Run Code Online (Sandbox Code Playgroud)
这条线应该适合你:
[NSKeyedUnarchiver unarchivedObjectOfClass:NSArray.class fromData:data error:&err];
Run Code Online (Sandbox Code Playgroud)