Xcode 13 and iOS 15 began warning about missingAllowedClasses when using custom DataTransformers. There is very little documentation on custom DataTransformers, so I thought I would post a question and answer it here.
[general] *** -[NSKeyedUnarchiver _warnAboutPlistType:missingInAllowedClasses:] allowed unarchiving safe plist type ''NSString' (0x1dc9a7660) [/System/Library/Frameworks/Foundation.framework]', even though it was not explicitly included in the client allowed classes set: '{(
    "'NSArray' (0x1dc99c838) [/System/Library/Frameworks/CoreFoundation.framework]"
)}'. This will be disallowed in the future.
Notice in the warning message, it specifies 'NSArray' and the type missing, 'NSString'.
I faced this issue for userDefaults while saving custom models, and I fixed it by passing classes of [NSArray.self, NSString.self,NSNumber.self,CustomModel.self] to silence this warning.
Note: before iOS 15 I just passed an NSArray class, but now I have to pass other classes like NSString or NSNumber because my custom model has strings, numbers and arrays.
{
  decodeData = try NSKeyedUnarchiver.unarchivedObject(
    ofClasses: [NSArray.self, NSString.self, NSNumber.self, CustomModel.self], from: customModel
  ) as? [CustomModel]
}
Here is an array value transformer that received the new warning, but no longer does since NSString was added:
// 1. Subclass from `NSSecureUnarchiveFromDataTransformer`
@objc(ArrayValueTransformer)
final class ArrayValueTransformer: NSSecureUnarchiveFromDataTransformer {
    
    static let name = NSValueTransformerName(rawValue: String(describing: ArrayValueTransformer.self))
    // 2. Make sure `NSArray` is in the allowed class list. However, since the array can also contain strings, be sure to include NSString.self in the allowedTopLevelClasses
    override static var allowedTopLevelClasses: [AnyClass] {
        return [NSArray.self, NSString.self] // Added NSString.self here to fix warning
    }
    /// Registers the transformer.
    public static func register() {
        let transformer = ArrayValueTransformer()
        ValueTransformer.setValueTransformer(transformer, forName: name)
    }
}
You can also silence warnings if using:
return try? NSKeyedUnarchiver.unarchivedObject(ofClasses:from:) by passing the same array that is specified in the return of allowedTopLevelClasses to the ofClasses parameter.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With