Reputation: 6037
I'd like to have the name field of a core data object be trimmed before it's saved to the context. My idea was to use the validation function for this. The following implementation works:
@objc
public func validateName(_ value: AutoreleasingUnsafeMutablePointer<AnyObject?>) throws {
guard let trimmedValue = (value.pointee as? String)?.trimmingCharacters(in: .whitespaces) else {
return
}
if name != trimmedValue {
name = trimmedValue
}
}
Without the if statement which sets the name field only in case of a change, core data throws an exception because of a cycle.
Now I have to questions:
Upvotes: 0
Views: 107
Reputation: 70976
Validation does this because, as you've found, any time you set a value, the validation function gets called. To change a value while validating, you need to bypass validation using setPrimitiveValue(_:forKey:)
instead of setting name
as usual. So, setPrimitiveValue(trimmed, forKey: "name")
or similar.
Validation is probably not the best time to do this. You'll need to refresh any views displaying the object data, for example. There are some other options.
One is via didChangeValue
, something like this:
public override func didChangeValue(forKey key: String) {
if key == "name", let name = self.name {
let trimmedValue = nametrimmingCharacters(in: .whitespaces)
setPrimitiveValue(trimmedValue, forKey: "name")
}
super.willChangeValue(forKey: key)
}
You could also use willSave
, and use the object's changedValues()
to see if the name changed.
The right way to do it-- as far as Core Data is concerned, anyway-- is to override the setter for name
. Unfortunately you need to turn off automatic code generation for Core Data to do that. I described the process in this answer: Using property observers on NSManaged vars
Upvotes: 1