问题描述
在我的 Core Data 架构中,我在一个实体中有一个“可转换”属性,该属性使用 NSValueTransformer
,其目的是通过某种压缩将 UIImage 转换为 NSData。从这个属性,我最近开始收到这些关于使用 NSKeyedUnarchiveFromData
的警告:
'NSKeyedUnarchiveFromData' 不应用于取消归档和 将在以后的版本中删除
所以我读到了这个 (link) 并认为我需要将 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
作为可转换属性的自定义类,将 ImageToDataTransformer
作为值转换器名称。
让我们知道它是否有效。