.transformable with ValueTransformer failing after Xcode 15.1 update

In Xcode 15.0.1, I created a new project to start working with SwiftData. I did this by creating a default App project and checking the Use SwiftData checkbox. The resulting project contains just three files: an app entry point file, a ContentView SwiftUI view file, and an Item model file.

The only change I made was to annotate the default Item timestamp property with a .transformable attribute.

Here is the resulting model:

@Model
final class Item {
	@Attribute(.transformable(by: TestVT.self)) var timestamp: Date // Only updated this line
	
	init(timestamp: Date) {
		self.timestamp = timestamp
	}
}

And here is the definition of TestVT. It is a basic ValueTransformer that simply tries to store the Date as a NSNumber:

// Added this
class TestVT: ValueTransformer {
	static let name = NSValueTransformerName("TestVT")
	
	override class func transformedValueClass() -> AnyClass {
		NSNumber.self
	}
	
	override class func allowsReverseTransformation() -> Bool {
		true
	}
	
	override func transformedValue(_ value: Any?) -> Any? {
		guard let date = value as? Date else {
			return nil
		}
		
		let ti = date.timeIntervalSince1970
		
		return NSNumber(value: ti)
	}
	
	override func reverseTransformedValue(_ value: Any?) -> Any? {
		guard let num = value as? NSNumber else {
			return nil
		}
		
		let ti = num.doubleValue as TimeInterval
		
		return Date(timeIntervalSince1970: ti)
	}
}

And finally, I made sure to register my ValueTransformer but updating the sharedModelContainer definition in the App:

var sharedModelContainer: ModelContainer = {
		ValueTransformer.setValueTransformer(TestVT(), forName: TestVT.name) // Only added this line
		let schema = Schema([
			Item.self,
		])
		let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
		
		do {
			return try ModelContainer(for: schema, configurations: [modelConfiguration])
		} catch {
			fatalError("Could not create ModelContainer: \(error)")
		}
	}()

Prior to Xcode 15.1, this was working fine. However, now when I try to create an item when running the app I get the following error: Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unacceptable type of value for attribute: property = "timestamp"; desired type = NSNumber; given type = __NSTaggedDate; value = 2023-12-14 01:47:11 +0000.'

I'm unsure of why this stopped working. The error seems to be complaining about the input being of type Date when NSNumber was expected, but I thought that's what the ValueTransformer was supposed to be doing.

Important note: prior to Xcode 15.1, I did not originally override the transformedValueClass() and everything was working but in the new Xcode when launching the app I was getting a Thread 1: EXC_BAD_ACCESS (code=1, address=0x0) on the return try ModelContainer(...) line. Removing the .transformable property from my model fixed the issue. That's why I added the override here, because I think the docs indicate overriding it as well and I missed that the first time. This being said, I think the code I have is what a correct ValueTransformer would look like.

If anyone has experienced this issue, or has a working ValueTransformer for SwiftData in Xcode 15.1, please let me know. Appreciate any help with this issue. Thanks so much!

Post not yet marked as solved Up vote post of Sammcb Down vote post of Sammcb
581 views

Replies

I am facing the same issue, this was working perfectly fine for me in Xcode 15.0.1, I just tested my app using Xcode 15.2 Beta and I'm getting Thread 1: EXC_BAD_ACCESS (code=1, address=0x0) on the same line where I try to create a model container ModelContainer(...) looks like a regression to me. I would open a Feedback

  • I have a feedback open FB13471979

  • Seems to be an issue only with iOS 17.1.0+ and above this seems fine on iOS 17.0.1 which makes it feel like a regression to me

Add a Comment

My understanding and usage of ValueTransformer was that the AnyClass returned from:

override class func transformedValueClass() -> AnyClass

was the expected type to be returned from:

override func transformedValue(_ value: Any?) -> Any?

This allowed for the value parameter passed to transformedValue to be Any? as defined by the function declaration.


In Xcode 15.1 (iOS simulator 17.0.1) I was able to accept a SIMD3<Float> as the value parameter in my override of transformedValue and return a NSData. This matched my interpretation as detailed above.

I was able to succesfully transform a SIMD3<Float> to NSData and implement reverseTransformedValue taking a NSData for its value parameter and returning a SIMD3<Float>.

SwiftData would store and retrieve my SIMD3<Float> using my value transformer as expected.


In Xcode 15.1 (iOS simulator 17.2) I get the error:

    Thread 1: "Unacceptable type of value for attribute: property = \"cameraPosition\"; desired type = NSData; given type = __SwiftValue; value = SIMD3<Float>(0.0, 0.0, 1.0)."

This would imply

override func transformedValue(_ value: Any?) -> Any?

is now expecting / enforcing the value parameter should be the same type as the return from

override class func transformedValueClass() -> AnyClass

(in this case NSData) which is different to how the API worked in the iOS17.0.1 simulator.


This cannot be right as it enforces only class types (AnyClass) can be transformed. Surely the idea is to be able to tranform any type (Any) to any type (Any) even if it is via a class (AnyClass) type.

The ValueTransformer nomencleture and parameter types do not clearly specify the API's intended usage clearly.


I have not been able to find any reference to this issue in release notes.

I will assume this is a regression and will continue to use the iOS 17.0.1 simulator (as far as possible) in the meantime hoping a fix or revised ValueTransformer guidelines.

  • Seems to be an issue only with iOS 17.1.0+ and above this seems fine on iOS 17.0.1 which makes it feel like a regression to me

Add a Comment

I am seeing the same exact error using Xcode 15.3. / VisionOS 1.1 simulator.

  • Also occurring on VisionOS 1.2 simulator.

Add a Comment