iOS 11 - Core Data - UIColor no longers works as transformable attribute

妖精的绣舞 提交于 2019-12-01 03:16:49

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

The text I got from apple:

/* 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));

/* 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));

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.

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];

EDIT: 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;
}

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

George did all the hard work. I only applied it to Swift. Here is my solution. I put it into my NSPersistentDocument descendant.

override func configurePersistentStoreCoordinator(for url: URL, ofType fileType: String, modelConfiguration configuration: String?, storeOptions: [String : Any]? = nil) throws {
    var options = storeOptions != nil ? storeOptions! : [String:Any]()
    if #available(OSX 10.13, *) {
        options[NSBinaryStoreSecureDecodingClasses] = NSSet(object: NSColor.self)
    }
    options[NSMigratePersistentStoresAutomaticallyOption] = true
    options[NSInferMappingModelAutomaticallyOption] = true
    try super.configurePersistentStoreCoordinator(for: url, ofType: fileType, modelConfiguration: configuration, storeOptions: options)
}

Now I can read my files again. Thanks George!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!