Geo*_*own 10 xcode core-data objective-c ios11 macos-high-sierra
我使用可转换属性将颜色存储在我的二进制Core Data存储中,将属性的类指定为UIColor,如下所示:
#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
Run Code Online (Sandbox Code Playgroud)
在iOS 11 Beta中,这已经停止了这样的错误:
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";
}
Run Code Online (Sandbox Code Playgroud)
我设法在GitHub上的XCode项目中复制特定问题(必须与XCode Beta一起运行两次以获得错误).
在示范项目的存储类型由NSPersistentStoreDescription控制,将其设置为NSBinaryStoreType,这是我在AppDelegate中的exanple项目做,我在应用程序didFinishLaunchingWithOptions添加对象,否则就从核心数据的iOS11应用程序的标准模板.加上一个小的数据模型和类.
如果你运行项目两次,第一次创建数据存储区,一切都很好.第二次,数据存储区尝试打开并崩溃应用程序.如果我使用SQL支持的数据存储区,这个问题似乎只与二进制数据存储区有关.但是,我的应用程序在野外并使用二进制.
我已经向苹果公司报告了它作为一个错误,并在开发者论坛上寻求帮助,但Apple没有承认这个错误,也没有任何帮助.
随着iOS11发布日期的临近而我没有解决方案,我有点担心,我的应用程序只能在iOS11中运行.
我已经尝试将属性更改为NSData并查看是否可以取消归档数据,但它似乎仍然以某种方式内部存储为UIColor,并且数据库无法打开.
任何人都可以看到解决方法吗?我有野外的应用程序,并可能推出更新以转换数据存储区,然后iOS11可以为一些人工作,但这并不能保证所有用户得到修复程序,他们可能会丢失他们的数据.
编辑1:雷达编号:33895450
编辑2:我刚刚发现,这适用于核心数据中的任何可转换属性,错误消息中支持的值只是默认属性类型.
编辑3:出于好奇,我填写了transformable属性的所有字段(以前从未需要).我将"NSKeyedUnarchiveFromData"添加到核心数据实体的值变换器名称中,它应该是默认值,但您永远不会知道.没有效果.无论如何它必须使用值变换器才能知道它是UIColor.我填写自定义类字段为UIColor,没有效果.
编辑5:我之前注意到UIColor现在支持NSSecureCoding,如果安全性在某种程度上是在键入的其他商店中被忽略的问题.
编辑:现在iOS已经发布,我已经使用了我的一个TSI来进一步升级.如果我必须使用一个来修复他们的软件,我会把它们还给我吗?
编辑:Apple在我的TSI上回复了我,他们说它正在调查中,没有解决方法,并等待bug.他们退还了我的TSI,因为他们无能为力.
编辑8:macOS High Sierra上的问题相同,使用NSColor而不是UIColor.
Apple仍未向我提供有关我的实际错误报告的任何反馈.
好吧,Apple回到我身边,有了新的persistentStore选项!
我从苹果公司得到的文字:
/ *允许开发人员提供在解码二进制存储区时应使用的其他类集(必须实现NSSecureCoding)。使用此选项比使用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));
目前尚不清楚,但基本上,您必须在打开持久性存储时提供一个NSSet类,这些类用作可转换属性,并且符合NSSecureCoding的选项。
我的使用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];
Run Code Online (Sandbox Code Playgroud)
编辑:为使用NSPersistentStoreDescription打开核心数据持久性存储的新方法添加了解决方案。该代码基于当前的核心数据模板。
- (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;
}
Run Code Online (Sandbox Code Playgroud)
我还用分支中的修复程序更新了gitHub项目
| 归档时间: |
|
| 查看次数: |
947 次 |
| 最近记录: |