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