views:

1246

answers:

3

I'm creating a base class that has an isDirty flag. It is set any time one of its properties changes, but since it's a base class, it doesn't know what its properties are. So basically, on every subclass, I have to override every - set: method to something like this:

- (id) setName:(NSString *)value {
  if ([name isEqualToString:value]) {
    return;
  }
  [name autorelease];
  name = [value retain];
  isDirty = YES;  //Here's the important bit
}

Almost every line of that is what the automatically-synthesized setter would do. Is there any way I can override what @synthesize actually creates?

There are other options I have come up with, but they all seem like they would be much slower at runtime than this method. I've thought of things like adding an object to observe its own property changes, or creating a generic function to do all that and just pass in the address to the iVar and the new value, but that still requires overriding the setter.

Any ideas? If it makes a difference, it's for an iPhone app.

+6  A: 

There's no way I know of that enables you to override what @synthesize does.

At the end of the day, it's used for creating basic accessor methods - ie. those that don't have specific behaviour.

Maybe you should look into Key Value Coding and Key Value Observing?

Jasarien
As I mentioned, I had thought of observing the changes, but it would be slower than doing it the way I am now, so I'll just deal with it.
Ed Marty
Again-- have you actually measured it? If your -setName: method is being called so often that KVO is measurable overhead, there is very likely a serious design flaw in your application.
bbum
It's not just -setName, obviously. As I said, I'm designing a base class that may have any object subclass with any variable.
Ed Marty
+3  A: 

There isn't.

What you want to achieve is only possible by digging deep into the Objective-C runtime or by using proxy objects.

Why don't you have a look at KVO again?

Georg
+6  A: 

Several issues here:

(1) If you are concerned about setter performance, you shouldn't be using -isEqualToString: in your setter. Do a pointer compare instead because that is all that matters in this context.

(2) If you have an NSString attribute, you should be copying on set. Copy is free for immutable strings and will save your bacon for mutable strings (by preventing the caller from mutating the string out from under you).

(3) Again with performance; you checked for equality, but then use autorelease. That incurs unnecessary overhead.

(4) * they all seem like they would be much slower at runtime* indicates that you haven't actually tried it, haven't identified a performance problem, and are prematurely optimizing your code. Given (1) and (3), there is likely much more easily addressed performance issues.

My suggestions:

(1) Use @synthesize. It will generate correct and fast code, addressing (1) and (3).

(2) Use KVO or one of the other mechanisms. Until you identify a performance problem through instrumentation and quantification, you don't have a performance problem.

(3) Consider using CoreData (unless, of course, you are targeting OS 2.x). The example code is from something that is obviously a model object. If your code is nicely factored into model/view/controller, using CoreData at the model layer can both simplify your application and CoreData does a wonderful job of change tracking.

bbum
As for 1, I'm using isEqualToString because if they are different strings that have the same contents, I don't want to set the isDirty flag.I haven't tried the other methods, but it seems common sense to me that sending more messages means it takes longer. Don't you think?
Ed Marty
Not until you measure it. Sending -copy to immutable strings, even when copying the value that was already there, is going to be faster than calling -isEqualToString; on two different immutable strings.
bbum
(Unless, of course, the response to isDirty: is significantly costly. If that is the case, then you are better off revisiting why your code is resetting the same value.
bbum
I'm not quite sure I follow your comment. I want to set the boolean iVar isDirty = YES if and only if the value coming in is not the same value as it was before. How would I determine that without using isEqualToString?
Ed Marty
Don't change the value unless the user has done something to change it, for example.
bbum
But then what if the user changes it, then manually changes it back before saving it?
Ed Marty