导致更新的属性

这个对象,Shape 有一个属性 image,取决于 numberOfSidessideWidth。如果设置了其中任何一个,则必须重新计算 image。但重新计算可能很长,只需要设置两个属性就可以完成一次,因此 Shape 提供了一种设置两个属性并且只重新计算一次的方法。这是通过直接设置属性 ivars 来完成的。

Shape.h

@interface Shape {
    NSUInteger numberOfSides;
    CGFloat sideWidth;

    UIImage * image;
}

// Initializer that takes initial values for the properties.
- (instancetype)initWithNumberOfSides:(NSUInteger)numberOfSides withWidth:(CGFloat)width;

// Method that allows to set both properties in once call.
// This is useful if setting these properties has expensive side-effects.
// Using a method to set both values at once allows you to have the side-
// effect executed only once.
- (void)setNumberOfSides:(NSUInteger)numberOfSides andWidth:(CGFloat)width;

// Properties using default attributes.
@property NSUInteger numberOfSides;
@property CGFloat sideWidth;

// Property using explicit attributes.
@property(strong, readonly) UIImage * image;

@end

Shape.m

@implementation AnObject

// The variable name of a property that is auto-generated by the compiler
// defaults to being the property name prefixed with an underscore, for
// example "_propertyName". You can change this default variable name using
// the following statement:
// @synthesize propertyName = customVariableName;

- (id)initWithNumberOfSides:(NSUInteger)numberOfSides withWidth:(CGFloat)width {
    if ((self = [self init])) {
       [self setNumberOfSides:numberOfSides andWidth:width];
    }

    return self;
}

- (void)setNumberOfSides:(NSUInteger)numberOfSides {
    _numberOfSides = numberOfSides;

    [self updateImage];
}

- (void)setSideWidth:(CGFloat)sideWidth {
    _sideWidth = sideWidth;

    [self updateImage];
}

- (void)setNumberOfSides:(NSUInteger)numberOfSides andWidth:(CGFloat)sideWidth {
    _numberOfSides = numberOfSides;
    _sideWidth = sideWidth;

    [self updateImage];
}

// Method that does some post-processing once either of the properties has
// been updated.
- (void)updateImage {
    ...
}

@end

当属性被分配给(使用 object.property = value)时,调用 setter 方法 setProperty:。这个 setter,即使由 @synthesize 提供,也可以被覆盖,就像在这种情况下 numberOfSidessideWidth 一样。但是,如果你直接设置属性的 ivar(如果对象是 self 或 object->property,则通过 property),它不会调用 getter 或 setter,允许你执行多个属性集,只调用一个更新或旁路侧 - 设定者造成的影响。