9

在 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的正确方法是什么,这样我就不会陷入无限循环?

4

3 回答 3

21

您应该能够直接以_scale. 您的 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];
    }

}
于 2012-10-31T16:36:53.790 回答
2

点表示法起初可能会有点误导。

二传手

在您在此处发布的行中

self.scale = scale;

您没有分配给局部变量。实际上,您将消息发送-setScale:self. 这条线相当于

[self setScale:scale];

由于您是-setScale:从内部调用的-setScale:,因此您将获得这种无限递归。

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

@property (nonatomic) CGFloat scale;

您已经创建了一个实例变量_scale但是,由于您还覆盖了-scale-setScale:,因此不会创建此实例变量。因此,您需要自己添加实例变量。在您的班级声明@interface中(或者,在班级扩展 @interface中)

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

完成此操作后,将行更改为

_scale = scale;

吸气剂

您还发布了另外两条有问题的行,它们在 getter 中。第一个是

return self.scale;

里面- (CGFloat)scale。与以前类似,这个点符号并不意味着你可能认为它的意思。事实上,这意味着

return [self scale];

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

if (!self.scale) {

出于同样的原因,这是一个问题:表达式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在 setter 中调用,因此您仍然需要它。

- (void)setScale:(CGFloat)scale
{
    if (_scale != scale) {
        _scale = scale;
        [self setNeedsDisplay];
    }
}
于 2012-10-31T16:39:19.193 回答
2

好吧,我可以想到大约 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 并将其设置为非法值。
0 通常对于您的测试来说是一件非常糟糕的事情,因为您可能非常希望 0 成为有效值。

于 2012-10-31T17:01:59.957 回答