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
,比如说,由100PointView
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不实现该方法。”不管怎样,调用超类方法是更好的做法吗?是的,总是调用超-这就是上下文指针很重要的原因。例子: