6

假设我们有这个CustomButton接口:

@interface CustomButton : UIButton
    @property (nonatomic, assign) CGFloat minWidth;
@end

每次minWidth改变,我们都要CustomButton重新布局。据我所知,我们有两种解决方案:

观察财产的价值

// In -initWithFrame:
[self addObserver:self forKeyPath:@"minWidth" options:0 context:nil];

// In -observeValueForKeyPath:ofObject:change:context:
[self setNeedsLayout];

覆盖minWidth的设置器

// In -setMinWidth:
_minWidth = minWidth; // Side note: it's an ARC project
[self setNeedsLayout];

哪一个是正确的解决方案,为什么?

4

2 回答 2

5

我可以想到 3 个理由来覆盖 setter 而不是 KVO 属性。

1:副作用可能会有所不同

除非您明确需要或想要副作用,否则阻力最小的路径(或在这种情况下的开销)是覆盖设置器。KVO 不仅涉及到给定属性的绑定,还涉及观察者在整个绑定期间都处于活动状态的假设。甚至不要让我开始谈论 KVO 的调试难度有多大!臭名昭著的“ NSKVODeallocateBreak断点”足以吓跑任何人。

2:传统智慧

“观察自己”虽然在理论上是一个好主意,但比重写 setter 更难。KVO 也是 setter 之上的额外(但最小)开销,仅对绑定到其他对象真正有用。此外,如果您将一个类视为一个自包含的单元,那么它确实不需要观察其自身的任何属性。Setter 精确地存在,因此给定的类可以选择对其属性的更改做出反应,甚至拒绝或修改所述更改。

3:我们都很懒

通过观察自己,你现在已经遵守了 KVO 的规则:即记住将自己移除为观察者,并实施

-observeValueForKeyPath:ofObject:change:context:.

相对于手头的任务,这是太多的工作为什么你要记住要做所有这些?

于 2013-03-20T22:35:44.393 回答
0

正确答案实际上在您的问题中:

每次更改 minWidth 时,我们都想重新布局 CustomButton。

编程没有绝对的答案,这使它既是一门艺术又是一门科学。但是,您可以采用一些策略来确保编程行为不会妨碍您尝试实现或创建的目标。编程本身就是达到目的的一种手段。

因此,您的代码应该尽可能复杂,但仅此而已。

虽然您可以使用键值对观察,并且没有人会责怪您,但更好的方法(在您的问题的上下文中)是覆盖设置器,因为这是您的意图(上面引用),它最简单,最简洁和字面形式。

在放大的层面上,您的代码应该尽可能易于阅读和解析,以便这些简单的块可以组装成更复杂的结构。如果放大到最详细的代码是不必要的冗长或复杂,这将表现为整个项目的摩擦(更难调试,更容易出错,等等)。

于 2013-03-20T23:10:47.500 回答