Reputation: 2101
How to implement custom setter for NSManagedObject
in Swift. I need to do task before setting the NSMangedObject
Property.
Upvotes: 10
Views: 5138
Reputation: 9925
I would recommend overriding awakeFromInsert
instead of the init
because it doesn't require KVO and the object properties can be accessed safely. Overriding any of the init
methods is risky and unnecessary since the object + its properties may not be ready to be accessed (faults).
Overriding any of the init
methods is risky and unnecessary since the object + its properties may not be ready to be accessed (faults). However, it’s very useful to be able to prepare an NSManagedObject
before it starts accepting data. Perhaps we want to set up some logical defaults or assign some relationships before handing the object to the user. In these situations, we use awakeFromInsert
. As the name implies, this method is called right after the NSManagedObject
is created from an insert call.
This method is called before any values are set and is a perfect opportunity to set default values, initialize transient properties, and perform other tasks that we would normally handle in the init
method. This method is called exactly once in the entire lifetime of an object. It won’t be called on the next execution of the application, and it won’t be called when an object is read in from the persistent store. Therefore, we don’t need to worry about overriding values that have been set previously. When we override this method, we should be sure to call super.awakeFromInsert()
at the very beginning of our implementation to allow the NSManagedObject
to finish anything it needs to before we begin our code.
NOTE: It's very easy to add your own Swift snippet for this manually. You can also try some GH repo. e.g for Swift 4 snippets.
Upvotes: 0
Reputation: 80273
My recommendation would be to use KVC. Maybe not the most elegant solution, but conceptionally a logical application of KVC.
Observe a change of the attribute. Register for the change in init(entity:insertIntoManagedObjectContext:)
or maybe better in awakeFromFetch
and awakeFromInsert
, and remove the observer in willTurnIntoFault
.
init(entity: NSEntityDescription!, insertIntoManagedObjectContext context: NSManagedObjectContext!) {
super.init(entity: entity, insertIntoManagedObjectContext: context)
addObserver(self, forKeyPath: "attribute", options: NSKeyValueObservingOptions.New | NSKeyValueObservingOptions.Old, context: nil)
}
override func observeValueForKeyPath(keyPath: String!, ofObject object: AnyObject!, change: NSDictionary!, context: CMutableVoidPointer) {
if (keyPath == "attribute") {
// do what you need to do
}
}
Updated for Swift 3:
init(entity: NSEntityDescription!, insertIntoManagedObjectContext context: NSManagedObjectContext!) {
super.init(entity: entity, insertIntoManagedObjectContext: context)
addObserver(self, forKeyPath: "attribute", options: [.old, .new], context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "attribute" {
// do what you need to do
}
}
Upvotes: 9
Reputation: 1208
There is even a simpler way how to do it without managing KVO subscription. It can be done simply by overriding didChangeValueForKey:
like this:
override func didChangeValueForKey(key: String) {
super.didChangeValueForKey(key)
if key == "propertyName" {
// do something now when propertyName changed
}
}
Upvotes: 7