Using one setter for all model iVars

2019-03-04 01:53发布

问题:

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).

回答1:

Use Key-Value Observing. You have to manually register yourself as an observer for every property, though.