swiftcore-datatransformablenssecurecoding

Secure coding of Set<CustomObject>


My app uses core data, which stores instances of a custom class CustomClass.
This class has a number of properties, most of them of standard types, but one property is xxx: Set<CustomObject>.
The xcdatamodeld thus specifies (among the others with standard types) an attribute xxx of type Transformable. xxx is the Set<CustomObject>. Its type is Optional and the Transformer is now NSSecureUnarchiveFromData.
Earlier the Transformer was not specified, and thus decoding was not secure. But Apple now advises to use secure coding, since insecure coding will be deprecated in future.

To enable secure coding, I did the following:
CustomClass now adopts NSSecureCoding instead of NSCoding.
The following var was added to CustomClass:

public static var supportsSecureCoding: Bool { get { return true } }  

Then I tried to modify public required convenience init?(coder aDecoder: NSCoder) {…} so that attribute xxx is securely decoded. I know that instead of

let xxx = aDecoder.decodeObject(forKey: „xxx“) as? Set<CustomObject>  

I have to use now decodeObject(of:forKey:), where of is the type of the object to be decoded, here type Set<CustomObject>.
My problem is that I don’t know how to formulate this: If I use

let xxx = aDecoder.decodeObject(of: Set<CustomObject>.self, forKey: „xxx“)  

I get the error Cannot convert value of type 'Set<CustomObject>.Type' to expected argument type '[AnyClass]?' (aka 'Optional<Array<AnyObject.Type>>‘).
Apparently the compiler did not compile

func decodeObject<DecodedObjectType>(of cls: DecodedObjectType.Type, forKey key: String) -> DecodedObjectType? where DecodedObjectType : NSObject, DecodedObjectType : NSCoding  

but instead

func decodeObject(of classes: [AnyClass]?, forKey key: String) -> Any?

i.e. it treated Set<CustomObject> not as a single type, but as a collection of types.

So, how do I specify that only a single type should be decoded, namely Set<CustomObject>?


Solution

  • Unfortunately, I could not find anything in the Apple docs, but I found a hint to the solution in this post:
    NSSecureCoding is not available for all standard swift classes. For those classes, that don’t support it, one has to use the Objective-C counterpart classes, i.e. NSString instead of String.

    One example: If var string = "String" has to be securely encoded, one has to use e.g. aCoder.encode(string as NSString, forKey: „string“).

    Now currently Set is not supported by NSSecureCoding. I had to use thus

    let aSet: Set<CustomObject> = []
    aCoder.encode(aSet as NSSet, forKey: „aSet“)  
    

    and

    let decodedSet = aDecoder.decodeObject(of: NSSet.self, forKey: „aSet“) as? Set<CustomObject>