在我的核心数据模式中,我在一个实体中有一个'transformable'属性,它使用NSValueTransformer
,其目的是将UIImage转换为NSData与一些压缩。从这个属性,我最近开始得到这些关于使用NSKeyedUnarchiveFromData
的警告:
'NSKeyedUnarchiveFromData'不应该用于取消存档和将在将来的版本中删除
所以我读了这个(链接),并认为我需要将NSValueTransformer
改为使用NSSecureUnarchiveFromDataTransformer
…但是在进行了更改之后(就像我从文章中理解的那样),我无法让它工作,现在当访问属性时应用程序崩溃了。
这是现有的NSValueTransformer
:
@interface ImageToDataTransformer : NSValueTransformer {
}
@implementation ImageToDataTransformer
+ (BOOL)allowsReverseTransformation {
return YES;
}
+ (Class)transformedValueClass {
return [NSData class];
}
- (id)transformedValue:(id)value {
// for our smaller views this uses much less data and makes for faster syncing
NSData *compressedData = UIImageJPEGRepresentation(value, 0.4);
return compressedData;
}
- (id)reverseTransformedValue:(id)value {
UIImage *uiImage = [[UIImage alloc] initWithData:value];
NSData *data = (NSData *) value;
//NSLog(@"reverseTransformedValue: image size: %@", [NSByteCountFormatter stringFromByteCount:data.length countStyle:NSByteCountFormatterCountStyleFile]);
return uiImage;
}
所以我把它从NSSecureUnarchiveFromDataTransformer
改为子类,并添加以下实现:
+ (NSArray<Class> *)allowedTopLevelClasses {
return @[[ImageToDataTransformer class]];
}
+ (void)setValueTransformer:(nullable NSValueTransformer *)transformer forName:(NSValueTransformerName)name {
NSLog(@"ImageToDataTransfer: calling setValueTransformer");
[NSValueTransformer setValueTransformer:transformer forName:name];
}
+ (NSArray<NSValueTransformerName> *)valueTransformerNames {
return @[@"ImageToDataTransformerName"];
}
然后,在访问Core Data持久存储之前,我'注册'转换器:
[ImageToDataTransformer setValueTransformer: [[ImageToDataTransformer alloc] init] forName:@"ImageToDataTransformerName"];
现在警告消失了,但是当读取图像时应用程序崩溃了:
-[__NSCFData _rasterizedImage]:无法识别的选择器发送到实例0x7ff53c108800
如果我把变压器变回NSValueTransformer
,它工作得很好。所以我不确定我是否从实现中错过了一些东西,或者我误解了'NSSecureUnarchiveFromDataTransformer'的前提。我很想知道我能做些什么来解决这个问题。
我认为您不需要重写+valueTransformerNames
和+setValueTransformer:forName:
类方法。
从文档中看来,它们不应该被重写,因为第一个类方法将返回在调用时实际注册的值转换器名称。第二个方法是你如何注册你的值转换器。所以你应该删除这两个被覆盖的方法。
你可以在你的值转换器的+load
类方法中注册你的值转换器,在你的应用程序中发生任何其他事情之前,如下所示:
NSValueTransformerName const ImageToDataTransformerName = @"ImageToDataTransformer";
+ (void)load
{
[ImageToDataTransformer setValueTransformer:[[ImageToDataTransformer alloc] init]
forName:ImageToDataTransformerName];
}
然后重写+allowedTopLevelClasses
以返回允许的顶层可转换类,它只是UIImage类,如下所示:
+ (NSArray<Class> *)allowedTopLevelClasses
{
return @[[UIImage class]];
}
然后在Core Data模式中将UIImage
作为transformable属性的自定义类,并将ImageToDataTransformer
作为值转换器的名称。
让我们知道它是否有效。