2

在我的核心数据模式中,我在实体中有一个“可转换”属性,该属性使用 a 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”的前提。很想知道我能做些什么来解决这个问题。

4

1 回答 1

0

我认为您不需要覆盖+valueTransformerNamesand+setValueTransformer:forName:类方法。

从文档看来,它们不应该被覆盖,因为第一个类方法将返回调用时实际注册的值转换器名称。第二种方法是您实际注册价值转换器的方式。所以你应该删除这两个覆盖的方法。

您可以+load在您的应用程序中发生任何其他事情之前,在您的价值转换器的类方法中注册您的价值转换器,如下所示:

NSValueTransformerName const ImageToDataTransformerName = @"ImageToDataTransformer";

+ (void)load
{
    [ImageToDataTransformer setValueTransformer:[[ImageToDataTransformer alloc] init]
                                        forName:ImageToDataTransformerName];
}

然后重写+allowedTopLevelClasses以返回允许的顶级可转换类,即 UIImage 类,如下所示:

+ (NSArray<Class> *)allowedTopLevelClasses
{
    return @[[UIImage class]];
}

然后在您的核心数据模式中,将UIImage其作为可转换属性的自定义类,并ImageToDataTransformer作为值转换器名称。

让我们知道它是否有效。

于 2021-03-21T20:08:06.363 回答