I have a series of models for my application. Across all these models there are (will be) some 200 or 300 instance variables. The application stores its persistent data on a web-based server (MySQL - but I guess that part doesn't matter). Whenever a model iVar is updated I need to make a call to the server to update the appropriate value for that iVar.
My current model strategy is (header file):
@interface MyModel : NSObject {
NSString * firstName;
NSString * lastName;
}
@property (readwrite, copy) NSString * firstName;
@property (readwrite, copy) NSString * lastName;
@end
(implementation file):
@implementation MyModel
@synthesize firstName;
@synthesize lastName;
-(id)init {
[super init]
[self setFirstName:@"George"];
[self setLastName:@"Kastanza"];
return self;
}
-(void)setFirstName:(NSString *)aName {
// call method to update server with new value here
firstName = aName;
}
-(void)setLastName:(NSString *)aName {
// call method to update server with new value here
lastName = aName;
}
@end
The problem is that if I have 200 or 300 iVar's all needing to go through the same update call to the server that means writing a lot of setters. Moreover, if I need to make a change to the method call, I'd have to update each and every method in every setter i the entire application.
Is there a process by which I could run every set of an iVar through a method first, before setting?
I thought of having just a NSMutableDictionary
per model object to store all of the iVar's, but that abstracts the setters and getters and may introduce a big memory footprint for so many dictionaries. However, doing it this way means that every time the dictionary is set I could pass it through one method.
As I understand it dynamically adding iVar's at runtime to an object model is considered a bad thing because of the pointer referencing for any subclasses that may be dependent upon the model (the subclass pointer doesn't get offset unless a complete recompile is done).
Any ideas and suggestions much appreciated.
Update
Based upon Ole's recommendation here is the solution (although it uses a little more code than a few lines unfortunately)...
In the model I added a method that I can set when I need to. I didn't call the method directly from the init, because adding a whole bunch of results returned from the server would trigger the observers for every object added. So I call the method after I have initialized and updated the first grab from the server.
Here's the code...
-(void)registerObservers {
[self addObserver:self
forKeyPath:@"firstName"
options:NSKeyValueObservingOptionNew
context:NULL];
[self addObserver:self
forKeyPath:@"lastName"
options:NSKeyValueObservingOptionNew
context:NULL];
}
Then I add the observer to the model:
-(void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
if ([keyPath isEqual:@"firstName"]) {
// Do whatever I need to do
}
if ([keyPath isEqual:@"lastName"]) {
// Do whatever I need to do
}
}
In my real implementation I also happen to post a notification of the object set to self
so that I can update anything that should be listening but isn't paying attention (like stuff in NSArrayControllers
).
Use Key-Value Observing. You have to manually register yourself as an observer for every property, though.