Hello,
I have a question about data deserialization using NSKeyedUnarchiver in iOS SDK development.
Current Situation:
- Previously, we were using the NSKeyedUnarchiver.unarchiveObject(with: Data) function
- We have changed to using the NSKeyedUnarchiver.unarchivedObject(ofClasses:from:) method to deserialize complex objects stored in UserDefaults
- We need to include all types in the ofClasses parameter, including Swift primitive types as well as various custom classes and structs within the project
Questions:
- Implementation Approach: Is it correct pattern to include all classes defined in the project in the ofClasses array? Is this approach recommended?
- Runtime Stability: When using this approach, is there a possibility of runtime crashes? Are there any performance issues?
- Alternative Methods: If the current approach is not the correct pattern, what alternatives should we consider?
Current Code Structure:
- All model classes conform to the NSSecureCoding protocol
- We use the requiringSecureCoding: true parameter
- We use a whitelist approach, explicitly listing only allowed classes
I would like to know if this structure is appropriate, or if we should consider a different approach.
Thank you.
Is it correct pattern to include all classes defined in the project in the ofClasses array?
Probably not, but it depends on how the object graph was serialised in the first place. The general idea with coding is that each class is responsible for encoding and decoding its own values. With secure coding that means that each class is responsible for decoding its values securely. So, if a class X has an array property whose elements are expected to be of type Y, it calls decodeArrayOfObjects(ofClasses:forKey:) passing Y to the first parameter. If class Y has a propert of type Z, class X doesn’t need to list it here because it’s handled by Y internally.
So, when you call unarchivedObject(ofClasses:from:) you only have to list the class of the root object. In most setups that a single class, not a long list.
When using this approach, is there a possibility of runtime crashes?
That question is too general to answer.
Are there any performance issues?
If you’re asking whether secure coding is slower than regular coding then the answer is “yes”. It has to do more work and thus is guaranteed to be slower.
However, it’s likely to be a trivial difference. Moreover, if you’re concerned about performance, you shouldn’t be storing the resulting archive in UserDefaults.
If the current approach is not the correct pattern, what alternatives should we consider?
My general advice is that you move to Swift Codable. It’s generally less work and is secure by default.
Note that Codable does have limits, for example, it can only deal with hierarchies, not graphs. Moreover, to migrate from secure coding to Codable you have to sort out secure coding first, so whatever work you do on that front won’t be wasted.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"