NSSecureUnarchiveFromData is now necessary for transformable attributes but does not work with Core Data CloudKit?

On iOS 13 for transformable attributes that have no custom Transformer class set this appears in the console:


"One or more models in this application are using transformable properties with transformer names that are either unset, or set to NSKeyedUnarchiveFromDataTransformerName. Please switch to using "NSSecureUnarchiveFromData" or a subclass of NSSecureUnarchiveFromDataTransformer instead. At some point, Core Data will default to using "NSSecureUnarchiveFromData" when nil is specified, and transformable properties containing classes that do not support NSSecureCoding will become unreadable."


This message appears on devices, in the simulator on High Sierra it even leads to a crash.


However, setting the transformer class to NSSecureUnarchiveFromDataTransformer when using CoreData CloudKit, this crashes and leads to Core Data not being initialized.


Disabling CloudKit, e.g. setting the .cloudKitContainerOptions on the store description to nil fixes this crash.


It seems CoreData CloudKit does not support NSSecureCoding transformers yet, right?

If that's the case, I don't know why this appears in the console. Is this just a bug?


To experience this for yourself, make an Xcode project with Core Data CloudKit and a transformable attribute, e.g. type [String: Int] in the model. Then set NSSecureUnarchiveFromData as the transformer for this attribute and try to start the app using this Core Data model with CloudKit enabled, meaning the Core Data Stack uses NSPersistentCloudKitContainer. In this case the Core Data model won't initialize.


I'm not that familiar with the different transformer classes, maybe I'm just doing something wrong? Without CloudKIt enabled it seems to work though!

Replies

I've now found that this is error 134060:

CloudKit integration requires that the value transformers for transformable attributes are available via +[NSValueTransformer valueTransformerForName:], return instances of NSData, and allow reverse transformation:

entity: attribute - Claims to return instances of nil


I didn't set the attribute to nil but NSSecureUnarchiveFromDataTransformerName.

I'll let the transformer name empty for now (which works with core data). Would indeed setting no transformer name default to NSSecureUnarchiveFromData at some point and CloudKit Core Data does not support this until then, I handle this by setting .cloudKitContainerOptions to nil whenever error.code 134060 comes up, disabling the Sync (which is better then a crashing app at least).


Does someone have any insight or a better idea? Any input is appreaciated!

Facing the same issue as well. Any insight?

Would love to gain insights or tips / best practices on how to handle this as well. It should be an issue that almost all Core Data CloudKit apps face and it would be really nice to know how to handle it correctly!

I'm experiencing the same or similar problem.


I suspect, but I am not certain, that it is a bug and I'll try to explain my reasons why... but first...


My scenario:


Xcode 11.3 project developing for iOS 13.x and beginning to implement NSPersistentCloudKitContainer.


I have `Transformable` type attributes for two Entities in my data model (for some time now). Incidentally both these attributes are used to store an optional value for Measurement<UnitMass>, which I understand from my reseach, conforms to `Encodable` and is therefore able to "just work" with a Core Data attribute of type `Transformable`. Others have written more on the capabilities of the Foundation `Measurement` class, using more accurate language than me, in this and other forums, so I'll leave this part of my description short.


As I am still in development with my Xcode project, I regularly switch between NSPersistentContainer and NSPersistentCloudKitContainer for testing purposes. This requires regularly resetting the development environment using the CloudKit Dashboard.


To ensure my app loads and runs regardless of which type of persistent container I am currently using, I also enable `NSPersistentHistoryTrackingKey = true`. This ensures that records persisted while my project's "container" is of type NSPersistentContainer are also available while my project's "container" is of type NSPersistentCloudKitContainer.


I recently updated my .xcdatamodel to add new attributes and new relationships to three entities. Two fo these entities contained the aforementioned attributes used to store optional values for Measurement<UnitMass>. Of these two, both contained renamed attributes and implemented the Renaming ID offered by lightweight migration. I reiterate here for clarity that these renamed attributes were not those used to store optional values for Measurement<UnitMass>, but did belong to the same entity.


It seems to me that I was experiencing compounding problems...


Intially my errors were related to your first error code: "One or more models in this application are using transformable properties with transformer names that are either unset, or set to NSKeyedUnarchiveFromDataTransformerName..." etc.


I admit here that I'm not proficient in the use of value transformers or the use of the `Transformable` attribute type... So I hacked away for some time, attempting to apply NSSecureUnarchiveFromData in the Transformer setting in the Attribute Inspector for each of the two attributes that were of type `Transformable`. This didn't seem to have any effect, so I began testing this on other "devices".


To make matters more confusing, I was experiencing different errors depending on what testing platform I was using and when I last updated that app's model - so in fact I was experiencing three different errors - Simulator with iPhone 8 Plus running iOS 13.3, Simulator with iPad Pro 12" 3rd generation running iOS 13.3, on device (iPhone 8 Plus) running iOS 13.3. I eventually deleted the instances of the app on the Simulators, but was extremely reluctant to do so on device due to the large amount of test data installed. Yes I am aware that I could download that and reinstall, but honestly I wanted to try to "fix" this problem.


One of the errors included commentary on the inability of Core Data to rename attributes that are related to CloudKit records.


So my three errors in fact this led me in part to my solution... roll back the data model. I reverted back to an earlier stable data model file that I knew did not cause any errors and ran it succesfully on the previously mentioned devices.


Going forward, I didn't attempt to change/update the attribute names as I had previously... for my next change in the data model I added the "new" attributes, then in the subsequent change in the data model I deleted the "old" attribute. Each time I ran the app on all three devices and received no errors. (Note: I accepted some minor data loss in records where old relationships were nullified on deletion.)


I reiterate here that all this was completed in a development environment in CloudKit.


I regret not recording the exact details of the three different types of errors... but they all began with "One or more models in this application are using transformable properties with transformer names that are either unset, or set to NSKeyedUnarchiveFromDataTransformerName." etc.


Hope this essay is of some help.

Did you solve the problem? I am facing the same problem.

I agree that this seems to be a CloudKit-only bug.


Take the Apple sample code at https://developer.apple.com/documentation/coredata/handling_different_data_types_in_core_data


Modify as needed to use CloudKit and it breaks with this error:


Fatal error: ###persistentContainer: Failed to load persistent stores:Error Domain=NSCocoaErrorDomain Code=134060 "A Core Data error occurred." UserInfo={NSLocalizedFailureReason=CloudKit integration requires that the value transformers for transformable attributes are available via +[NSValueTransformer valueTransformerForName:], return instances of NSData, and allow reverse transformation:

Book: tintColor - Claims to return instances of UIColor}: file /Users/conrodi/Downloads/HandlingDifferentDataTypesInCoreData/CoreDataAttributes/AppDelegate.swift, line 22


I've seen the same problem in other CloudKit projects. I think CloudKit is broken for Transformable Core Data attributes.

Same for me. I leave the field "Value Transformer Name" as blank in the panel "Attribute" and it doesn't crash now.

Does iOS 14 change any of this? In the same boat now and Xcode beta is telling me this if I remove the value transformer:

'NSKeyedUnarchiveFromData' should not be used to for un-archiving and will be removed in a future release
This is still an issue for me as well. Anybody have any updates?
I was able to remove the warnings by registering a new value transformer. I'm persisting a CLLocation, which conforms to NSSecureCoding.

Code Block swift
import Foundation
import CoreLocation
@objc(CLLocationValueTransformer)
final class CLLocationValueTransformer: NSSecureUnarchiveFromDataTransformer {
    static let name = NSValueTransformerName(rawValue: String(describing: CLLocationValueTransformer.self))
    override static var allowedTopLevelClasses: [AnyClass] {
        return [CLLocation.self]
    }
    public static func register() {
        let transformer = CLLocationValueTransformer()
        ValueTransformer.setValueTransformer(transformer, forName: name)
    }
}

Adding CLLocationValueTransformer as the transformer name works without warnings. The value is synced properly via NSPersistentCloudKitContainer, verified on multiple devices.
I am getting the same error message and I am NOT using CloudKit.....just CoreData.