Objective-c properties - getters and setters

In a subclass of UIView, I have this property:

@property (nonatomic) CGFloat scale; #define DEFAULT_SCALE 0.90 

and this getter and setter:

 -(CGFloat)scale { if (!self.scale) { return DEFAULT_SCALE; }else{ return self.scale; } } -(void)setScale:(CGFloat)scale { if (scale != self.scale) { self.scale = scale; [self setNeedsDisplay]; } } 

This is not true because, for example, checking self.scale in a getter causes an infinite loop. What is the correct way to write getter and setter so that I don't get an infinite loop?

+6
source share
3 answers

You must have ivar access directly as _scale . Then your getter / setter would look like this:

Update. As pointed out by @ wattson12 in the comments below, you need to add @synthesize to your implementation.

 @synthesize scale = _scale; -(CGFloat)scale { if (!_scale) { return DEFAULT_SCALE; }else{ return _scale; } } -(void)setScale:(CGFloat)scale { if (scale != _scale) { _scale = scale; [self setNeedsDisplay]; } } 
+14
source

Point notation can be misleading at first.

Setter

In the line you posted here

 self.scale = scale; 

you are not assigning a local variable. In fact, you send the -setScale: message to self . This line is equivalent

 [self setScale:scale]; 

Since you call -setScale: from -setScale: you get this infinite recursion.

What you need to do is set the instance variable in your setter (instead of invoking your setter from within itself). Usually just by writing

 @property (nonatomic) CGFloat scale; 

You have created the _scale instance _scale . However , since you also redefined both -scale and -setScale: this instance variable will not be created. Therefore, you will need to add the instance variable yourself. In the declaration of your @interface class (or, alternatively, in the extension of the @interface class )

 //If adding the instance variable to the class declaration: @interface MyClass : Superclass { //.... CGFloat _scale; } //.... @end 

After that, just change the line to

 _scale = scale; 

Getter

There are two other problematic lines that you posted, this is in the getter. First -

 return self.scale; 

inside - (CGFloat)scale . Just like before, this dotted notation does not mean what you think it means. It actually means

 return [self scale]; 

As before, this causes infinite recursion. Second -

 if (!self.scale) { 

This is a problem for the same reason: the expression self.scale when evaluating [self scale]. Again, this leads to infinite recursion. The fix for both of them is to replace self.scale with _scale , leaving you with this recipient:

 - (CGFloat)scale { if (!_scale) {//Since CGFloat is not an object, this means <<if (_scale == 0) {>> return DEFAULT_SCALE; } else { return _scale } } 

The best way

You do a lot more work here than you should be. It would be much better to use your initializer:

 - (id)initWithFrame:(NSRect)frame { self = [super initWithFrame:frame]; { self.scale = DEFAULT_SCALE; } } 

This ensures that if scale not set, it will return DEFAULT_SCALE . This allows you to completely eliminate getter (and therefore @synthesize ). Since you call -setNeedsDisplay on the setter, you still need to.

 - (void)setScale:(CGFloat)scale { if (_scale != scale) { _scale = scale; [self setNeedsDisplay]; } } 
+1
source

Well, I can think of 3 ways to do this and be aware.

 @interface someClass { BOOL useCustomScale; } @property float scale; @end @implimentation someClass -(float)scale { if(useCustomScale) {return scale;} return defaultScale; } -(void) setScale: (float)someScale { useCustomScale = YES; scale = someScale } 

else you can use NSNumber to support the scale value ...
otherwise, you can initialize the scale to -1 and make it an illegal value in the installer.
0 is generally very bad to use for your test, because you can really want 0 to be a valid value.

+1
source

All Articles