Ios 使用KVO观察多个对象的同时变化

Ios 使用KVO观察多个对象的同时变化,ios,objective-c,cocoa-touch,key-value-observing,Ios,Objective C,Cocoa Touch,Key Value Observing,我有一个LineView类,它显示两点之间的一条线。线视图本质上只是一个矩形视图,其厚度表示高度,其起点和终点的位置决定矩形的宽度以及我(使用CGAffineTransform)对矩形应用的旋转 @interface LineView : UIView @property (nonatomic) float thickness; @property (nonatomic, strong) (PointView *)startPoint; @property (nonatomic, strong)

我有一个
LineView
类,它显示两点之间的一条线。
线视图
本质上只是一个矩形视图,其
厚度
表示高度,其
起点
终点
的位置决定矩形的宽度以及我(使用
CGAffineTransform
)对矩形应用的旋转

@interface LineView : UIView
@property (nonatomic) float thickness;
@property (nonatomic, strong) (PointView *)startPoint;
@property (nonatomic, strong) (PointView *)endPoint;
PointView
类定义屏幕上的移动点。由于我希望直线始终显示在其起点和终点之间,因此我让
线视图
观察
起始点
终点
中心
属性,如下所示:

- (void)setStartPoint:(PointView *)startPoint
{
    // Un-observe previous startPoint
    [_startPoint removeObserver:self forKeyPath:@"center"];
    _startPoint = startPoint;
    // Observe new startPoint
    [_startPoint addObserver:self forKeyPath:@"center" options:0 context:nil];
    [self updateLine];
}
(void)setEndPoint:(PointView*)endPoint
的定义类似。因此,无论何时
center
属性发生更改,我都要更新该行:

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    if (![keyPath isEqualToString:@"center"])
    {
        return;
    }
    if (object == self.startPoint || object == self.endPoint)
    {
        [self updateLine];
    }
}
下面是
(void)updateLine:

- (void)updateLine
{
    CGPoint startPoint = self.startPoint.center;
    CGPoint endPoint = self.endPoint.center;

    // tangent vector
    CGPoint tangent = cgpSubtract(endPoint, startPoint);

    // determine the angle of the tangent vector
    float angle = cgpAngle(tangent);
    // determine the length of the tangent vector
    float length = cgpLength(tangent);

    // frame is undefined when transform is not identity
    self.transform = CGAffineTransformIdentity;
    // set frame.origin to startPoint, and frame.size to length and thickness
    self.frame = CGRectMake(startPoint.x, startPoint.y, length, self.thickness);
    // rotate the view so that the line properly connects startPoint and endPoint
    self.transform = CGAffineTransformMakeRotation(angle);

    [self setNeedsDisplay];
}
cgp
函数只是我定义的静态方法,用于执行简单的
CGPoint
数学

因此,每当
startPoint
endPoint
在屏幕上移动时,移动点的
center
属性会发生变化,
LineView
会观察到这种变化,并调用
updateLine
来更新自身

现在让我们假设
startPoint
endPoint
随着时间的推移在屏幕上移动。事实上,我们有一个带有
currentTime
属性的
Timeline
类:

@interface Timeline : NSObject
@property (nonatomic) float currentTime;
...
PointView
类被设置为观察此
currentTime
属性,并在
currentTime
更改时更改其
中心位置

这样,
点视图
依赖于
时间线
线视图
依赖于两个
点视图
,但
线视图
不依赖于
时间线
。它不需要知道什么是
currentTime
,只需要知道它的起点和终点的
中心的位置。这是个好设计,对吗

因此,当
currentTime
更改时,
startPoint.center
endPoint.center
都更改,然后
LineView
对象的
updateLine
被调用两次。理想情况下,我只希望调用一次
updateLine
,因为我实际上只需要更新一次行,以反映“同时”对这两个点所做的更改。有什么好办法吗

在本例中,两次调用
updateLine
似乎没什么大不了的。但是如果我定义某种类型的
PolygonView
,比如说,由100
PointView
s定义,会怎么样?然后,当我更新
currentTime
时,所有100个
PointView
s中的所有100个
center
s都会更新,而这又会调用
updatePolygon
100次,将
frame
transform
属性设置100次,这似乎效率很低

因此,这里的主要问题是,对于观察多个其他对象的对象,当观察到的对象“同时”更改时,而不是同时更改时,如何使该对象仅更新一次


我意识到“同时”这个词在这里并不恰当,因为这些变化不是同时处理的;每个
点视图都会在运行时按顺序更新。但是,我找不到更好的词来描述这种情况。

与您的问题无关,但不要忘记传递上下文指针,并确保您在observeValueForKeyPath中正确调用super。您提到了一系列依赖项,但没有提到实现+keypathsforvaluesfecting…..?@quellish没有在
observeValueForKeyPath
中调用
super
,只有在超类实现该方法时才需要
LineView
继承自
UIView
,而
UIView
类层次结构中似乎没有实现此方法。NSKeyValueObserving是NSObject上的非正式协议:我在看它在哪里说“如果超类实现了,一定要调用它的实现。NSObject不实现该方法。”不管怎样,调用超类方法是更好的做法吗?是的,总是调用超-这就是上下文指针很重要的原因。例子: