iOS 11-核心数据-UIColor不再充当可变形属性 [英] iOS 11 - Core Data - UIColor no longers works as transformable attribute

查看:104
本文介绍了iOS 11-核心数据-UIColor不再充当可变形属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用可变换的属性将颜色存储在二进制Core Data存储中,将属性的类指定为UIColor,如下所示:

I store colours in my binary Core Data store using a transformable attribute, specifying the class of the attribute as UIColor like so:

#import "CoreDataEntity+CoreDataClass.h"
#import <UIKit/UIKit.h>


NS_ASSUME_NONNULL_BEGIN

@interface CoreDataEntity (CoreDataProperties)

+ (NSFetchRequest<CoreDataEntity *> *)fetchRequest;

@property (nullable, nonatomic, retain) UIColor *transformable;
@property (nullable, nonatomic, copy)   NSString *string;

@end

NS_ASSUME_NONNULL_END

在iOS 11 Beta中,此操作已停止,并显示如下错误:

In the iOS 11 Beta this has stopped working with an error like this :

NSUnderlyingException=value for key 'NS.objects' was of unexpected class 'UIColor'. Allowed classes are '{(\n    NSDecimalNumber,\n    NSData,\n    NSUUID,\n    NSNumber,\n    NSDate,\n    NSArray,\n    NSOrderedSet,\n    NSDictionaryMapNode,\n    NSString,\n    NSSet,\n    NSDictionary,\n    NSURL,\n    NSNull\n)}'.}";
    NSUnderlyingException = "Can't read binary data from file";
}

我设法在GitHub上的XCode项目中复制了特定问题(必须与XCode Beta两次出现错误).

I managed to replicate the specific problem in an XCode project on GitHub (Must be run with the XCode Beta twice to get the error).

在演示项目中,商店类型由NSPersistentStoreDescription控制,并将其设置为NSBinaryStoreType,我在示例项目的AppDelegate中进行了此操作,并在应用didFinishLaunchingWithOptions中添加了对象,否则,这是带有核心的iOS11应用中的标准模板数据.加上一个小的数据模型和类.

In the demo project the store type is controlled by NSPersistentStoreDescription and setting it to NSBinaryStoreType, which I do in the AppDelegate in the exanple project, and I add objects in application didFinishLaunchingWithOptions, otherwise it's the standard template from an iOS11 app with core data. Plus a small datamodel and classes.

如果您运行该项目两次,则它是第一次创建数据存储,一切都很好.第二次,数据存储尝试打开并导致应用程序崩溃.据我所知,这个问题似乎仅与二进制数据存储有关,如果我使用SQL支持的数据存储,则它可以工作.但是,我的应用程序很疯狂,并且使用二进制文件.

If you run the project twice, the first time it creates the datastore and everything is fine. The second time, the datastore tries to open and crashes the app. This problem only seems to be related to binary datastores from what I can tell, if I use an SQL backed datastore it works. However, my app is in the wild and uses binary.

我已将其报告为Apple的错误,并在开发人员论坛上寻求帮助,但是Apple尚未确认该错误,并且没有帮助.

I've reported it to Apple as a bug and sought help on the developer forums, but Apple has not acknowledged the bug and no help was coming.

随着iOS11发行日期的临近,我有点担心,我没有解决方案,我的应用程序无法在iOS11中使用.

I'm getting a bit worried as the iOS11 release date draws nearer and I have no solution, my app just won't work in iOS11.

我尝试将属性更改为NSData并查看是否可以仅对数据进行归档,但是似乎它仍然以某种方式仍作为UIColor在内部存储,并且数据库无法打开.

I've tried changing the property to NSData and seeing if it was possible to just unarchive the data, but it seems it's still stored internally as a UIColor somehow and the database just won't open.

任何人都可以看到解决方法吗?我拥有该应用程序,并且可能在iOS11不能运行某些功能之前推出更新以转换数据存储,但这并不能保证所有用户都能获得修复,并且他们可能会丢失数据.

Can anyone see a workaround? I have the app in the wild, and possibly pushing out an update to convert the datastores before iOS11 could work for some, but that isn't going to guarantee all users get the fix and they could lose their data.

雷达号码:33895450

EDIT 1: Radar number : 33895450

在我看来,这适用于核心数据中的 any 可转换属性,错误消息中支持的值只是默认属性类型.

EDIT 2: It just occured to me that this applies to any transformable attribute in core data, the values supported in the error message are just the default property types.

出于好奇,我填写了transformable属性的所有字段(以前从未需要过). 我在核心数据实体的值转换器名称中添加了"NSKeyedUnarchiveFromData",它应该是默认值,但您永远不会知道.没有效果.无论如何,它必须使用值转换器才能知道它是UIColor. 我将自定义类字段填写为UIColor,没有效果.

EDIT 3: Just out of curiosity I filled out all the fields for the transformable attribute (it was never required before). I added "NSKeyedUnarchiveFromData" to value transformer name of the core data entity, it should be the default, but you never know. No effect. It must be using the value transformer anyway to know that it's a UIColor. I filled in the custom class field to be UIColor, no effect.

我早些时候注意到UIColor现在支持NSSecureCoding,应该以某种方式在其他键入的商店中忽略安全性.

Edit 5 : I noticed earlier that UIColor now supports NSSecureCoding, should security somehow be the issue somehow overlooked in the other store typed.

既然iOS已发布,我已经使用我的一个TSI来进一步升级它.如果我必须使用它们来修复软件,我应该找回它们吗?

Edit : Now that iOS is released, i’ve used one of my TSIs to further escalate this. Do i get them back if i have to use one to get them to fix their software?

苹果公司通过我的TSI给我回复,他们说它正在接受调查,没有解决方法,请耐心等待bug.他们因为无法帮助而退还了我的TSI.

Edit : Apple got back to me on my TSI, they said it’s under investigation, there is no workaround, and to wait on the bug. They refunded my TSI because they couldn’t help.

在macOS High Sierra上,使用NSColor而不是UIColor出现相同的问题.

Edit 8: Same problem on macOS High Sierra, with NSColor instead of UIColor.

Apple仍然没有对我的实际错误报告提供任何反馈.

Apple still have not given me any feedback on my actual bug report.

推荐答案

Apple告诉我,有新的persistentStore选项!

Well Apple got back to me, there are new persistentStore options!

我从苹果那里得到的文字:

The text I got from apple:

/*允许开发人员提供其他类集( 必须实现NSSecureCoding),该解码器应在解码 二进制存储.使用此选项比使用 NSBinaryStoreInsecureDecodingCompatibilityOption. */COREDATA_EXTERN NSString * const NSBinaryStoreSecureDecodingClasses API_AVAILABLE(macosx(10.13),ios(11.0),tvos(11.0),watchos(4.0));

/* Allows developers to provide an additional set of classes (which must implement NSSecureCoding) that should be used while decoding a binary store. Using this option is preferable to using NSBinaryStoreInsecureDecodingCompatibilityOption. */ COREDATA_EXTERN NSString * const NSBinaryStoreSecureDecodingClasses API_AVAILABLE(macosx(10.13),ios(11.0),tvos(11.0),watchos(4.0));

/*指示二进制存储应该被不安全地解码.这 如果商店具有元数据或可变换的属性,则可能有必要 包含非标准类.如果可能,开发人员应使用 NSBinaryStoreSecureDecodingClasses选项以指定包含的 类,从而可以安全地解码二进制存储. 在可用日期之前链接的应用程序将默认为使用 此选项. */COREDATA_EXTERN NSString * const NSBinaryStoreInsecureDecodingCompatibilityOption API_AVAILABLE(macosx(10.13),ios(11.0),tvos(11.0),watchos(4.0));

/* Indicate that the binary store should be decoded insecurely. This may be necessary if a store has metadata or transformable properties containing non-standard classes. If possible, developers should use the NSBinaryStoreSecureDecodingClasses option to specify the contained classes, allowing the binary store to to be securely decoded. Applications linked before the availability date will default to using this option. */ COREDATA_EXTERN NSString * const NSBinaryStoreInsecureDecodingCompatibilityOption API_AVAILABLE(macosx(10.13),ios(11.0),tvos(11.0),watchos(4.0));

目前尚不清楚,但基本上,您必须提供一个NSSet类,您将其用作可转换属性,并在打开持久性存储时将其作为符合NSSecureCoding的选项.

It's not immediately clear, but basically you have to supply an NSSet of classes you use as transformable attributes that comply with NSSecureCoding as an option when opening your persistent store.

使用UIColor的示例:

An example for mine using the UIColor :

NSError *localError;
NSDictionary *options;
if (@available(iOS 11.0, *)) {
    options = @{
                NSMigratePersistentStoresAutomaticallyOption : @YES,
                NSInferMappingModelAutomaticallyOption : @YES,
                NSBinaryStoreSecureDecodingClasses : [NSSet setWithObjects:[UIColor class], nil]
               };

} else {
    // Fallback on earlier versions
    options = @{
                NSMigratePersistentStoresAutomaticallyOption : @YES,
                NSInferMappingModelAutomaticallyOption : @YES,
                };
}
NSPersistentStore *newStore = [self.psc addPersistentStoreWithType:NSBinaryStoreType configuration:@"iOS" URL:psURL options:options error:&localError];

为使用NSPersistentStoreDescription打开核心数据持久性存储的新方法添加了解决方案.该代码基于当前的核心数据模板.

Adding a solution for the newer way to open core data persistent stores using NSPersistentStoreDescription. This code is based on the current core data template.

- (NSPersistentContainer *)persistentContainer {
    // The persistent container for the application. This implementation creates and returns a container, having loaded the store for the application to it.
    @synchronized (self) {
        if (_persistentContainer == nil) {
            NSURL *defaultURL = [NSPersistentContainer defaultDirectoryURL];
            defaultURL = [defaultURL URLByAppendingPathComponent:@"CoreDataTransformableAttribBug.binary"];
            _persistentContainer = [[NSPersistentContainer alloc] initWithName:@"CoreDataTransformableAttribBug"];
            NSPersistentStoreDescription *desc = [NSPersistentStoreDescription persistentStoreDescriptionWithURL:defaultURL];

            desc.type = NSBinaryStoreType;
            if (@available(iOS 11.0, *)) {
                [desc setOption:[NSSet setWithObjects:[UIColor class], nil] forKey:NSBinaryStoreSecureDecodingClasses];
            }
            _persistentContainer.persistentStoreDescriptions = @[desc];
            [_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
                if (error != nil) {
                    // Replace this implementation with code to handle the error appropriately.
                    // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

                    /*
                     Typical reasons for an error here include:
                     * The parent directory does not exist, cannot be created, or disallows writing.
                     * The persistent store is not accessible, due to permissions or data protection when the device is locked.
                     * The device is out of space.
                     * The store could not be migrated to the current model version.
                     Check the error message to determine what the actual problem was.
                    */
                    NSLog(@"Unresolved error %@, %@", error, error.userInfo);
                    abort();
                } else {
                    NSLog(@"Description = %@", storeDescription);
                }
            }];
        }
    }

    return _persistentContainer;
}

我还用分支中的修复程序更新了gitHub项目

I also updated my gitHub project with the fix in a branch

这篇关于iOS 11-核心数据-UIColor不再充当可变形属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆