[英]Why are my Cocoa bindings broken?
我有一个带有NSTextField的窗口(在Snow Leopard中),该窗口已绑定到WindowController类中的NSString函数。 此字符串将结合由阵列控制器提供的有关表视图的选择和计数的信息。 当选择或计数更改时,它将获得初始值"0 0"
,但不会更新。 绑定看起来像这样(文件的所有者是MyWindowController):
我实现了+ (NSSet *)keyPathsForValuesAffecting<key>
(如下所示),但是绑定永远不会更新,即使阵列控制器的总数和选择发生了变化。
( 执行了其他疑难解答 )我最初使用的是NSTextField的“显示模式值”绑定,但是我需要的逻辑比提供的绑定还要复杂。 然后,我开始侦听TableView的选择更改/更改事件,该事件显示了阵列控制器的内容,并动态更改了Display Pattern Value绑定,但是感觉像是hack,过于复杂。
我敢肯定我缺少什么,但我不知道是什么。 有人有什么想法吗? 我已经阅读了Apple的键值观察文档,这似乎是必需的。 我已经检查过了,我的keyPathsForValuesAffectingMyString
被调用了,但是myString
只被调用了一次。 我在下面提取了我的代码( 更新了x3 )。
更新1/21
我仍然想解决这个问题。 当我为arrayController键路径将self
addObserver
到self
,通知确实按预期触发,因此我的键路径和键值观察机制很好。 当我调用[self didChangeValueForKey:@"myString"];
在我的observeValueForKeyPath
方法中,对于相同的键,绑定仍然没有更新,这使我相信这是绑定问题,而不是KVO问题。 我将进一步阅读绑定机制...
@interface MyWindowController : NSWindowController {
IBOutlet NSArrayController *arrayController;
}
- (NSArrayController *)arrayController;
- (NSString *)myString;
@end
@implementation MyWindowController
+ (NSSet *)keyPathsForValuesAffectingMyString {
return [NSSet setWithObjects:
@"arrayController.arrangedObjects",
@"arrayController.selection",
nil];
}
- (NSArrayController *)arrayController {
return arrayController;
}
- (NSString *)myString {
// Just as an example; I have more complicated logic going on in my real code
return [NSString stringWithFormat:@"%@, %@",
[arrayController valueForKeyPath:@"arrangedObjects.@count"],
[arrayController valueForKeyPath:@"selection.@count"]];
}
@end
我已经验证了这个完全相同的错误。 Cocoabuilder上的某人猜测该错误的发生原因:
我不能说这个解释是否正确,但是我当然不能让+ keyPathsForValues…与NSArrayControllers一起工作。
我有一个解决方法,但是我对此并不满意,因为它不是必需的,我仍然希望绑定能够正常工作。 我不会接受此答案,如果有人发布了实际的修复程序,它将删除它。 </disclaimer>
@interface MyWindowController : NSWindowController {
IBOutlet NSArrayController *arrayController;
IBOutlet NSTextField *fieldThatShouldBeBinded;
}
- (NSString *)myString;
@end
@implementation MyWindowController
- (void)awakeFromNib {
[arrayController addObserver:self
forKeyPath:@"selection"
options:0
context:NULL];
[arrayController addObserver:self
forKeyPath:@"arrangedObjects"
options:0
context:NULL];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
if( object == arrayController )
[fieldThatShouldBeBinded setStringValue:[self myString]];
}
- (NSString *)myString {
return [NSString stringWithFormat:@"%@, %@",
[arrayController valueForKeyPath:@"arrangedObjects.@count"],
[arrayController valueForKeyPath:@"selection.@count"]];
}
@end
我遇到了同样的问题,并找到了另一种方法(但仍然可以解决)。 您必须声明动态解决方法属性。 在实现部分,只需为其返回一个新的空对象。 现在,您可以KVO此替代方法属性。
@property(nonatomic,retain) NSArray *workaround;
@dynamic workaround;
- (NSArray *)workaround { return [NSArray array]; } // new *every* time
- (void)setWorkaround:(NSArray *)unused { }
+ (NSSet *)keyPathsForValuesAffectingMyString { return [NSSet setWithObject:@"workaround"]; }
为了完成这项工作,您仍然需要手动将self.workaround
绑定到arrayController.selectedObjects
(或其他):
- (void)awakeFromNib // or similar place
{
[super awakeFromNib];
[self bind:@"workaround" toObject:arrayController withKeyPath:@"selectedObjects" options:nil];
}
手动绑定按预期方式工作,解决方法会根据您绑定的内容进行更新。 但是KVO会测试属性值是否确实发生了更改(如果相同则停止传播)。 如果您每次都返回新的self.workaround
值,它将起作用。
警告: 永远不要自己调用-[setWorkaround:]
-这将有效地刷新绑定的另一面(在这种情况下为arrayController.selectedObjects
)。
此方法有一些好处:避免使用集中的ObservValueForKeyPath:...并且逻辑位置正确。 而且扩展性很好,对于类似的情况,只需添加替代方法2、3,依此类推。
确保在Interface Builder中连接了arrayController
插座。 我猜是零。
不要使用@count关键字。 内容更改时,阵列控制器上的绑定和KVO将更新。 如果那不起作用,那么其他地方存在问题。
另一种选择是使用显示模式绑定而不是复合属性。 将显示模式值1绑定到arrayController.arrangedObjects。@ count并将显示模式值2绑定到arrayController.selection。@ count,并将模式设置为“%{value1} @,%{value2} @”
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.