以编程方式更改状态时,NSButton绑定失败

时间:2012-12-21 16:55:06

标签: xcode cocoa cocoa-bindings nsbutton

我有一个核心数据Mac App,具有不同的实体和属性...... 其中一个属性绑定到NSButton复选框...

这是我的问题: 如果我用鼠标点击按钮,我可以看到它的状态发生变化(例如从未检查到检查的例子),并且绑定属性的状态被保存到数据核心,因为如果我关闭并重新打开应用程序,按钮仍然被检查...

但是......

如果我以编程方式更改此按钮的状态,我仍然可以看到其状态发生变化(相同的例子,从未检查更改为已检查),但是绑定属性的状态未保存到数据核心,如果我关闭并重新打开应用程序,按钮返回未检查状态!

有什么想法吗?

修改

好吧,我会试着解释一下(抱歉我的英语不好)...

我必须使用名为Adherents的此实体的某些值进行一些操作和验证(例如,如果选中date1&gt; date2,则选中checkbox1,如果选中checkbox2,则无论日期比较如何都检查checkbox1)... < / p>

我首先指出了一个解决方案,我在“NSManagedObject子类文件Adherents.m

中使用此实体的值执行这些操作
- (void)awakeFromFetch{

 [super awakeFromFetch];


    // Controle de la cotisation
    aujourdhui = [NSDate date];
    finCotisation = [NSDate dateWithString:[dateCotisation description]];
    controle = [aujourdhui compare:finCotisation];
   if(controle == NSOrderedAscending)
   {
       self.cotisation = [NSNumber numberWithBool:1];
   }
    else if(controle == NSOrderedDescending)
    {
       if ([self.membreHonneur boolValue] == 0)
       {
            self.cotisation = [NSNumber numberWithBool:0];
        }
      else if ([self.membreHonneur boolValue] == 1)
       {
            self.cotisation = [NSNumber numberWithBool:1];
       }
    }
}

就像这样,操作只在应用程序启动时发生,这很好但不够...... 为了“在路上”(在用户通过NSDatePicker输入或更改日期之后),我建立的最佳解决方案是检查用户编辑日期选择器的时间...... 似乎我只能在AppDelegate.m文件中执行此操作(尝试在Adherents.h中声明“IBOutlet NSDatePicker * champDate;”,但后来,我无法使用Interface Builder中的复选框连接插座...),似乎我无法从那里访问和操作实体值(“self.cotisation”在AppDelegate.m中使用时会带来未知属性,我无法找到如何在AppDelegate.h中正确声明它)。

所以,我的解决方案是在AppDelegate中执行这些操作,比较NSDatePicker的值并对NSButton复选框状态进行操作...

- (void)awakeFromNib {

    [champDate setTarget:self];
    [champDate setAction:@selector(checkDate:)];

}

-(void)checkDate:(id)object {
   finCotisation = [NSDate dateWithNaturalLanguageString:[champDate stringValue]];
   aujourdhui = [NSDate date];
   NSComparisonResult controle = [aujourdhui compare:finCotisation];
    if(controle == NSOrderedAscending){
        [bouttonCotisation setState:TRUE];
    }
    else if(controle == NSOrderedDescending){
        [bouttonCotisation setState:FALSE];
   }
}

但是,当这样做时,绑定失败......所以,我必须做两件事:监视NSDatePicker并在我的AppDelegate.m中以编程方式更改复选框状态,并检查并使用Adherents.m中的AwakeFromFetch更改实体值,I当所有人都被绑定时,我认为这是一个很好的废话^^

1 个答案:

答案 0 :(得分:3)

我不确定我是否理解你问题的具体细节但是收集了这么多:

  • 从外部看,您的数据模型对象具有以下属性
    • 两个日期值
    • 布尔值
    • 第二个布尔值,它应具有不同的值,具体取决于其他三个值
  • 您只更新awakeFromFetch方法中的相关值,因此在运行时更改数据时不会更新,因此您可以在AppDelegate中手动更改复选框。

我发现这种方法存在两个问题:

  1. 使用绑定时,您应该只更改模型数据以更新UI,而不是直接调用UI元素的setter。
  2. 如果您拥有完全依赖于其他属性的属性,请不要单独保存(除了缓存原因,但这会使其更复杂)。只需动态计算即可。
  3. 我假设您的模型类看起来像这样:

    @interface
    @property (strong) NSDate *date1;
    @property (strong) NSDate *date2;
    @property (assign BOOL someBool;
    @end
    

    现在我们声明以与头文件相同的方式添加依赖属性:

    // readonly because it cannot be changed directly, only the values it depends on can be changed
    @property (assign, readonly) BOOL dependentBool;
    

    但是对于这个属性,我们自己在@implementation中实现了getter:

    -(BOOL)dependentBool
    {
        if (NSOrderedAscending = [self.date1 compare:self.date2])
            return YES;
    
        if (self.someBool)
            return YES;
    
        return NO;
    }
    

    这样,只要有人检查dependentBool属性,它就会返回正确的结果。您现在可以将复选框绑定到dependentBool。 但是,如果您更改任何取决于复选框的值将不会更新,因为它不知道值已更改。为了解决这个问题,我们将以下方法添加到模型类实现中:

    +(NSSet *)keyPathsForValuesAffectingDependentBool
    {
        return [NSSet setWithArray:@[@"date1", @"date2", @"someBool"]];
    }
    

    这告诉任何人观察dependentBool属性(当绑定到此属性时复选框将执行)依赖于这些键路径,因此也应该观察这些键路径。

    这样您就可以更改date1的值,例如,绑定到dependentBool的任何视图都会相应更改。

    注意:要使其正常工作,您必须通过其设置器([myModelObject setDate1:date]myModelObject.date1 = dateself.date1 = date)更改属性的值,而不是直接更改实例变量({{1 }})。

    我希望你能根据自己的需要调整这个例子。