iosswiftprotocolsnssecurecoding

Using decodeObject(of: forKey:) to decode an object that conforms to a protocol


I have an Objective-C protocol that requires conformance to NSSecureCoding:

@protocol MyProtocol <NSObject, NSSecureCoding>
…
@end

I have a parent object that stores a reference to an object conforming to MyProtocol, and I would like the parent object to also conform to NSSecureCoding. When I try this:

required init?(coder aDecoder: NSCoder) {

    if let childObject = aDecoder.decodeObject(of: MyProtocol.self, forKey: "childObject") {
        self. childObject = childObject
    } else {
        return nil
    }
}

I get the error: 'decodeObject(of:forKey:)' is unavailable in Swift: use generic 'decodeObjectOfClass(_:forKey:)'.

Is there any way to use NSSecureCoding if you don't know the specific class of the object you encoded?


Solution

  • The entire point of NSSecureCoding is to prevent this use case. If you do not know the class you are decoding, then an attacker can trick you into decoding into a class that behaves differently than the one you expected for a given method (called a "substitution attack"). This was a technique used to attack systems, and NSSecureCoding was developed to thwart it.

    Even if that weren't the case, it's not possible to construct an object of protocol type. The runtime would have no way to know how much memory to allocate for instance variables.

    In order to conform to NSSecureCoding, you must know the precise classes of all child objects.