objective-c属性 - getter和setter

时间:2012-10-31 16:31:37

标签: objective-c ios uiview getter-setter

在UIView子类中,我有这个属性:

@property (nonatomic) CGFloat scale;

#define DEFAULT_SCALE 0.90

这个getter和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];
    }

}

这是不正确的,因为例如在getter中检查self.scale会导致无限循环。编写getter和setter的正确方法是什么,这样我就不会得到无限循环?

3 个答案:

答案 0 :(得分:15)

您应该可以_scale直接访问ivar。你的getter / setter看起来像是:

更新:正如@ wattson12在下面的评论中指出的那样,您需要在实施中添加@synthesize

@synthesize scale = _scale;

-(CGFloat)scale
{
    if (!_scale) {
        return DEFAULT_SCALE;
    }else{
        return _scale;
    }
}

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

}

答案 1 :(得分:1)

Dot notation can be a tad misleading at first.

The Setter

在你发布的这一行中

self.scale = scale;

您没有分配给本地变量。实际上,您正在向-setScale:发送消息self。这一行相当于

[self setScale:scale];

由于您从-setScale:内部呼叫-setScale:,因此您将获得此无限递归。

您需要做的是在setter中设置一个实例变量(而不是从内部调用您的setter)。通常,只需写下

@property (nonatomic) CGFloat scale;

您已经创建了一个实例变量_scale,因为您还覆盖了-scale-setScale:,因此不会创建此实例变量。因此,您需要自己添加实例变量。在您的课程'声明@interface中(或者class extension @interface

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

完成此操作后,将线路更改为

就足够了
_scale = scale;

Getter

您发布了另外两个有问题的行,这些行在getter中。第一个是

return self.scale;

- (CGFloat)scale内。与之前类似,此点符号并不意味着您可能认为它意味着什么。事实上,这意味着

return [self scale];

和以前一样,这会导致无限递归。第二个是

if (!self.scale) {

出于同样的原因,这是一个问题:表达式self.scale,当评估时是[自我尺度]。同样,这会导致无限递归。对这两个问题的解决方法是将self.scale替换为_scale,让您使用此getter:

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

更好的方式

你在这里做的工作比你真正应该做的要多得多。利用初始化程序会好得多:

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

这将保证如果未设置scale,则会返回DEFAULT_SCALE。这允许您完全消除吸气剂(因此,@synthesize)。由于您在设置器中调用了-setNeedsDisplay,因此您仍然需要它。

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

答案 2 :(得分:1)

我可以想到有3种方法可以做到这一点,并且0知道。

@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
}

否则您可以使用NSNumber来支持比例值...
否则你可以将比例初始化为-1并将其设置为setter中的非法值 0通常是用于测试的非常糟糕的事情,因为您可能希望0成为有效值。