Search code examples
iosobjective-ccore-data

Saving an array of custom classes in Core Data


I am trying to save an array of custom classes in Core Data as a transformable attribute, but keep getting the following error when trying to load the saved data:

 NSSecureUnarchiveFromData transformer> threw while decoding a value. ({
    NSUnderlyingError = "Error Domain=NSCocoaErrorDomain Code=4864 \"value for key 'NS.objects' was of unexpected class 'MyCustomClass' 

In the Core Data schema I have set the transformer to "NSSecureUnarchiveFromData" and the Custom Class to "NSArray" (since I want to save an array of "MyCustomClass")

MyCustomClass.h

@interface MyCustomClass : NSObject <NSSecureCoding>

@property (nonatomic, assign) NSString *identifier;

MyCustomClass.m

@implementation MyCustomClass

+ (BOOL)supportsSecureCoding {
    
    return YES;
}

- (void)encodeWithCoder:(nonnull NSCoder *)coder {
    
    [coder encodeObject:self.identifier forKey:@"Identifier"];
}

- (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder {
    
    if (self = [super init]) {
        
        self.identifier = [coder decodeObjectOfClass:[NSString class] forKey:@"Identifier"];
    }
    
    return self;
}

I even tried to change the property declaration in "MyCustomClass+CoreDataProperties" to NSArray<MyCustomClass *> but got the same error.

What step am I missing or doing wrong please?


Solution

  • I was missing a few steps. In addition to the code in the question, the following had to be done to get this to work:

    • Change the attribute's Custom Class in the model editor to NSArray

    • Create a new class called MyCustomClassTransformer:

    @interface MyCustomClassTransformer: NSSecureUnarchiveFromDataTransformer {}
    @end
    
    @implementation MyCustomClassTransformer
    + (Class)transformedValueClass {
        return [MyCustomClassTransformer class];
    }
    + (BOOL)allowsReverseTransformation {
        return YES;
    }
    
    + (NSArray<Class> *)allowedTopLevelClasses {
        return @[[MyCustomClass class], [NSArray class]];
    }
    @end
    

    • Register new transformer in AppDelegate's "didFinishLaunchingWithOptions":

    MyCustomClassTransformer *transformer = [MyCustomClassTransformer new];
    [NSValueTransformer setValueTransformer:transformer forName: @"MyCustomClassTransformer"];