What is going on with transformable

Hi, I keep trying to use transformable to store an array of strings with SwiftData, and I can see that it is activating the transformer, but it keeps saying that I am still using NSArray instead of NSData.

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unacceptable type of value for attribute: property = "category"; desired type = NSData; given type = Swift.__SwiftDeferredNSArray; value = ( yo, gurt ).' terminating due to uncaught exception of type NSException CoreSimulator 1010.10 - Device: iPhone 16 18.0 (6879535B-3174-4025-AD37-ED06E60291AD) - Runtime: iOS 18.0 (22A3351) - DeviceType: iPhone 16 Message from debugger: killed

@Model
    class MyModel: Identifiable, Equatable {
        
        @Attribute(.transformable(by: StringArrayTransformer.self)) var category: [String]?
        
        @Attribute(.transformable(by: StringArrayTransformer.self)) var amenities: [String]?
        
        var image: String?
        
        var parentChunck: HenricoPostDataChunk_V1?
        
        init(category: [String]?, amenities: [String]?) {
            self.category = category
            self.amenities = amenities
        }
    }
class StringArrayTransformer: ValueTransformer {
    override func transformedValue(_ value: Any?) -> Any? {
        print(value)
        guard let array = value as? [String] else { return nil }
        let data = try? JSONSerialization.data(withJSONObject: array, options: [])
        print(data)
        return data
    }
    
    override func reverseTransformedValue(_ value: Any?) -> Any? {
        guard let data = value as? Data else { return nil }
        let string = (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String]
        print(string)
        return string
    }
    
    override class func transformedValueClass() -> AnyClass {
        return NSData.self
    }
    
    override class func allowsReverseTransformation() -> Bool {
        return true
    }
    
    static func register() {
        print("regitsering")
        ValueTransformer.setValueTransformer(StringArrayTransformer(), forName: .stringArrayTransformerName)
    }
}

extension NSValueTransformerName {
    static let stringArrayTransformerName = NSValueTransformerName("StringArrayTransformer")
}

Im also registering the transforming as soon as possible, and I am getting print statements indicating that they are being converted, so I am truly not sure what the issue is.

An easier solution is to wrap the string in a struct and use an array of that custom struct instead. Make sure the struct conforms to Codable.

Ideally we should be able to have just an array of String but that isn’t possible currently

@Jerome_Donfack There are two main requirements to use transformer in SwiftData:

  • The type returned by transformedValueClass needs to correspond to the type you declare in the model, so it needs to be changed to NSArray.self

  • transformedValue can only be encoded as NSData, and in CoreData, we can encode into any supported type, such as NSNumber, NSString


Override class func transformedValueClass() -> AnyClass {

Return NSArray.self // change to NSArray

}

BTW: If it is not to be compatible with your other custom data, SwiftData will use the built-in transaformer to encode [String] without using transformable

What is going on with transformable
 
 
Q