我一直不确定的一件事是如何正确处理自定义NSControl
子类和NSCell
子类之间的通信。在我对Cocoa的介绍中,我已经看到它多次提到父控件如何提供许多与子单元格/单元格实现相同的方法,访问器和变换器。例如,NSControl
类和NSCell
类在其头文件中都有-isEnabled
和-setEnabled:
:
NSControl.h
- (BOOL)isEnabled;
- (void)setEnabled:(BOOL)flag;
NSCell.h
- (BOOL)isEnabled;
- (void)setEnabled:(BOOL)flag;
我了解NSControl
类为NSCell
中找到的大多数属性提供了“封面”方法。我更感兴趣的是:它们是如何实现的?或者甚至更好,如何实现他/她自己的子类的共享属性?显然,只有Apple的工程师真的知道他们框架内部正在发生什么,但我想也许有人可以用一种很好的清洁方式来模仿Apple的封面方法方法。
我很难解释一些东西,所以我会提供一个我正在谈论的例子。假设我已经将NSControl
分类为:
BSDToggleSwitch.h
#import "BSDToggleSwitchCell.h"
@interface BSDToggleSwitch : NSControl
@property (nonatomic, strong) BSDToggleSwitchCell *cell;
@property (nonatomic, assign) BOOL sharedProp;
@end
我已经分组NSActionCell
:
BSDToggleSwitchCell.h
#import "BSDToggleSwitch.h"
@interface BSDToggleSwitchCell : NSActionCell
@property (nonatomic, weak) BSDToggleSwitch *controlView;
@property (nonatomic, assign) BOOL sharedProp;
@end
如您所见,他们共享一个名为sharedProp
的属性。
我的问题是:有效保持共享属性在控件和单元格之间同步的标准方法是什么?这看起来似乎是一个主观问题,我想是这样,但我想认为有一种最好的“最佳方式”来做到这一点。
我过去曾使用过各种不同的方法,但我想缩小处理它的方式,并且只使用能够以最低开销提供最佳数据完整性的技术。我应该使用绑定吗?如何实现调用其对应方匹配方法的自定义mutator?志愿?我是一个迷失的原因吗?
以下是我过去做过的一些事情(其中一些或全部可能完全是错误的或直接的错误):
Cocoa Bindings - 我只是将控件的属性绑定到单元格的属性(反之亦然):
[self bind:@"sharedProp" toObject:self.cell withKeyPath:@"sharedProp" options:nil];
这似乎是一个非常好的方法,但你会绑定/从哪个对象?我已经阅读了所有的KVO / KVC / Bindings文档,但是在任何一种情况下,当属性应该相同时,我从未真正了解绑定的方向性的重要性。是否有一般规则?
从Mutators发送消息 - 我会从控件的mutator发送一条消息:
- (void)setSharedProp:(BOOL)sharedProp
{
if ( sharedProp == _sharedProp )
return;
_sharedProp = sharedProp;
[self.cell setSharedProp:sharedProp];
}
然后我会在单元格的实现中做同样的事情:
- (void)setSharedProp:(BOOL)sharedProp
{
if ( sharedProp == _sharedProp )
return;
_sharedProp = sharedProp;
[self.controlView setSharedProp:sharedProp];
}
这似乎也很合理,但似乎也更容易出错。如果一个对象在没有值检查的情况下向另一个发送消息,则无限循环可能很容易发生,对吧?在上面的例子中,我为此添加了检查,但我确信有更好的方法
观察并报告 - 我会观察每个对象实现中的属性更改:
static void * const BSDPropertySyncContext = @"BSDPropertySyncContext";
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if ( context == BSDPropertySyncContext && [keyPath isEqualToString:@"sharedProp"] ) {
BOOL newValue = [[change objectForKey:NSKeyValueChangeNewKey] boolValue];
if ( newValue != self.sharedProp ) {
[self setSharedProp:newValue];
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
再一次,这似乎可行,但我不想为每个共享属性编写if
语句。沿着观察的路线,我也发送了通知,但由于控制单元关系与人们可以得到的“一对一”(甜蜜的双关语),这看起来很愚蠢。
同样,我知道这有点主观,但我真的很感激一些指导。我一直在学习Cocoa / Objective-C一段时间了,这从一开始就困扰着我。了解其他人如何处理控件和单元格之间的属性同步可能真的帮助我!
谢谢!
答案 0 :(得分:3)
首先,请注意,由于NeXT时代的性能问题,NSCell
主要存在。远离NSCell
的迁移速度很慢,除非您需要与需要它们的内容进行交互(例如使用NSMatrix
,或者如果您需要,否则通常不应创建新的迁移做一些看起来很像NSMatrix
的东西。请注意自10.7以来对NSTableView
的更改以淡化单元格,以及NSCollectionViewItem
如何是完整视图控制器。我们现在拥有处理能力,可以在大多数情况下仅使用视图而无需NSCell
。
也就是说,通常控件只是将消息转发给单元格。例如:
- (BOOL)sharedProp {
return self.cell.sharedProp;
}
- (void)setSharedProp:(BOOL)sharedProp {
[self.cell setSharedProp:sharedProp];
}
如果KVO是一个问题,你仍然可以与keyPathsForValuesAffectingValueForKey:
(和它的亲戚)挂钩。例如,您可以执行以下操作:
- (NSSet *)keyPathsForValuesAffectingSharedProp {
return [NSSet setWithObject:@"cell.sharedProp"];
}
这应该让您观察sharedProp
并透明地将更改转发给cell.sharedProp
。