How to provide additional custom implementation of accessor methods when using @synthesize?
-
19-09-2019 - |
Question
I want to fire some code when a property is accessed and changed. I use @property
and @synthesize
in my code for my ivars. The properties are retained, so I'd like to keep that memory management stuff automatically generated by @synthesize
.
However, I assume that @synthesize
tells the compiler to generate the accessor methods code right where @synthesize is
, so most of the cases at the top of the code, right?
And when I have a property foo
, I get -setFoo
and -foo
methods. Could I then just make a method like this, to execute some more custom code when a property is changed?
-(void)setFoo {
// custom stuff
}
Now that's a problem. How to execute the first one? I wouldn't love to have a different name here. Is there maybe a way to let the @synthesize
directive create other names for getter and setter methods, which I then call easily? And I would still be able to use the dot syntax then to access them?
Solution
You can use @property
and @synthesize
just like you normally would, but provide a custom setter or getter (or both) and those will be used instead. Typically I will do something like this:
// Override the setter
- (void)setName:(NSString *)aName
{
if (name == aName)
return;
[name release];
name = [aName retain];
//custom code here
}
When I use the set property, it will invoke my custom method. However, the get will still be synthesized.
OTHER TIPS
If you provide an implemnetation for the setters or getters it will use that instead of the generated implementation. Its not hard to implement the "retaining" aspect of the getters and setters that are generated for you by the compiler when u synthesize, so you can just write your own getters and setters i would say and go with that.
One wacky solution is to create an abstract super class that does gives you the normal property synthesis. Then create a concrete subclass that you will actually use, and that simply implements and override method (same signature) and calls super to do the actual setting. This allows you to do whatever you want to do before or after the call to super's implementation.
Example:
@interface ALTOClassA : NSObject
@property NSString *catName;
@end
Nothing else needed in the .m beyond the stubbed file for this test.
Create the subclass, nothing needed specially in the @interface
#import "ALTOClassA.h"
@interface ALTOClassAJunior : ALTOClassA
@end
In the @implementation we do our override.
#import "ALTOClassAJunior.h"
@implementation ALTOClassAJunior
- (void)setCatName:(NSString*)aCatName {
NSLog(@"%@",NSStringFromSelector(_cmd));
[super setCatName:aCatName];
NSLog(@"after super: self.catName %@", self.catName);
}
@end
In use:
ALTOClassAJunior *aCAJ = [ALTOClassAJunior new];
NSLog(@"aCAS.catName %@", aCAJ.catName);
NSLog(@"set it to George.");
[aCAJ setCatName:@"George"];
NSLog(@"aCAS.catName %@", aCAJ.catName);
This allows you to leverage the autogenerated code, and still do stuff you want to do with your class. Abstract Super Class is often a useful solution for many things.
Yes, in your @property declaration, you can specify the getter and setter methods.
@property (readwrite,getter=privateGetFoo,setter=privateSetFoo:) NSObject * foo;
In your foo
and setFoo:
methods, call [self privateGetFoo]
or [self privateSetFoo:f]
then your custom code.
The object can also set an observer on itself with addObserver:forKeyPath:options:context:
.
That said, I don't think either of these are very clean ways to do things. Better to write your own getter/setter as others have suggested.