1

Is it possible to write a UIView to disk using NSSecureCoding. The below code results in an error.

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:object requiringSecureCoding:YES error:&error];

Error: The data couldn’t be written because it isn’t in the correct format.

We also tried the following:

NSMutableData *data = [NSMutableData data];
NSKeyedArchiver  *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
[archiver encodeObject:view forKey:@"view"];
[archiver finishEncoding];

Error: This decoder will only decode classes that adopt NSSecureCoding. Class 'UIView' does not adopt it.

user1752054
  • 372
  • 4
  • 17
  • Why do you want to securely code a UIView? To my understanding, insecure coding has the problem that the unarchiver constructs an object graph that could be casted to something else that lets you inspect data in an unwanted way. I cannot imagine this situation applied to a UIView. But maybe you just must use secure coding because it is required, like for a Transformable attribute in CoreData. If so, maybe you could insecurely archive your UIView to a NSData object, and then securely code the NSData object? I know this is a hack and I don’t know if it works, but I don’t have another idea. – Reinhard Männer Jun 12 '21 at 16:07
  • Hi Reinhard, Thanks for your response. Exactly, we need to use secure coding because it is required. We attempting to archive and unarchive a mutable array that includes UIIView objects using secure coding. Unfortunately, archiving UIViews to NSData doesn't work and returns an error that the data is not in the correct format. – user1752054 Jun 12 '21 at 22:53

1 Answers1

2

NSSecureCoding, in addition to NSCoding requirements, simply requires the class to implement a class function +(BOOL)supportsSecureCoding. UIView already supports NSCoding and it seems like it might be an oversight that it doesn't already conform to NSSecureCoding; the Xcode debugger issues warnings about non-NSSecureCoding serialization calls going away in the distant future.

You can add the class function to UIView using a category:

@interface UIView(SecureCoding)<NSSecureCoding>
@end

@implementation UIView(SecureCoding)
+ (BOOL)supportsSecureCoding {
    return TRUE;
}
@end

So as pointed out in the comments, this doesn't mean that you'll be able to deserialize with the NSKeyedUnarchiver because it appears that UIViews weren't intended to be serialized that way. I'm guessing the main reason they support serialization is for xibs/nibs/storyboards. Here's an example of UIView serialization that DOES work, but uses private APIs, so it's for illustrative purposes only:

Add declarations to access unpublished APIs:

/* Warning: Unpublished APIs!*/
@interface UINibEncoder : NSCoder
- initForWritingWithMutableData:(NSMutableData*)data;
- (void)finishEncoding;
@end

@interface UINibDecoder : NSCoder
- initForReadingWithData:(NSData *)data error:(NSError **)err;
@end

Serialization/Deserialization:

/* This does NOT work */
NSKeyedArchiver  *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:NO];
[archiver encodeObject:object forKey:@"view"];
[archiver finishEncoding];
data = [archiver encodedData];


NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:data error:&error];
/* error: 'UIBackgroundColor' was of unexpected class 'UIColor' */
data = [unarchiver decodeObjectForKey:@"view"];


/* This DOES work, but don't use it in an app you plan to publish */
NSMutableData *mData = [NSMutableData new];
UINibEncoder *encoder = [[UINibEncoder alloc] initForWritingWithMutableData:mData];

[encoder encodeObject:object forKey:@"view"];
[encoder finishEncoding];

UINibDecoder *decoder = [[UINibDecoder alloc] initForReadingWithData:mData error:&error];
NSObject *myView = [decoder decodeObjectForKey:@"view"];
Eric Shieh
  • 697
  • 5
  • 11
  • Thanks for your response! We've tried that, but, unfortunately, it doesn't work. Unarchiving the data returns an error that the data isn't in the correct format. – user1752054 Jun 16 '21 at 14:49
  • That's a different problem than the one stated: If you set securing coding to FALSE/NO in your example, you'll still end up with the same serialization errors. Adding a deeper explanation to the answer to explain why... – Eric Shieh Jun 16 '21 at 18:09