In Core Data I can implement a custom NSManagedObject property getter/setter:
@objc var name: String {
get {
willAccessValue(forKey: #keyPath(name))
defer { didAccessValue(forKey: #keyPath(name)) }
let name = primitiveValue(forKey: #keyPath(name)) as? String
return name ?? ""
}
set {
willChangeValue(forKey: #keyPath(name))
defer { didChangeValue(forKey: #keyPath(name)) }
// Trimming is just an example, it could be any data cleanup.
let name = newValue.trimmingCharacters(in: .whitespacesAndNewlines)
setPrimitiveValue(name, forKey: #keyPath(name))
}
}
How to achieve that in a SwiftData @Model
? I don't want to create a second property based on a persisted one but have only a single property.
Why not 2 properties:
- If I add the computed property later on then I need to migrate the data to a new stored property name like
_name
or choose a new, second-rate computed property name likenameNew
. - The stored property cannot be private because the computed property is not available in
#Predicate
. - 1 property would be nicer because I don't really need 2 properties, I just want to clean the data in the setter.
There doesn't seem to be an easy solution using a single property. But it's possible to address the pain points.
Solution 1
@Attribute(originalName: "name")
is only needed if you change the stored property name fromname
to_name
and have data to migrate. If you forget this, the data will be deleted. ⚠️_name
isprivate(set)
to ensure clean data via thename
setter. It cannot be fully private because as a computed propertyname
is not available in#Predicate
.Solution 2
name2
stands for two-way (get and set).