我希望能够更改具有startDate和endDate的(日历)事件。还有一段时间。
这最后一个操作会触发第一个操作,触发第三个操作,这会触发第一个 ad无限(或当堆栈填满时)。
如下所示的行更改值,导致此循环:
[self setValue:[NSNumber numberWithLong:(interval%60)] forKeyPath:@"durationMinutes"];
[self setValue:ed forKeyPath:@"endDate"];
简单地停止观察,并在更改后重新启动,因为GUI中的值不会更新,所以没有吸引力。 那么问题是:我如何安全(并且优雅地)更新两个相互依赖的属性之一?
答案 0 :(得分:6)
您可以在必要时使用setPrimitiveValue:forKey:
绕过KVO通知。设置值但不触发任何通知。它还绕过了您可能拥有的任何自定义设置器。这应该会打破通话周期。
使用此方法时,通常需要调用“将更改”和“更改”方法以确保维护Core Data状态。就是这样:
[self willChangeValueForKey:@"endDate"];
[self setPrimitiveValue:ed forKey:@"endDate"];
[self didChangeValueForKey:@"endDate"];
这避免了对标志的需要 - 你只是说,嘿,设定价值并且没有搞乱,好吗?
答案 1 :(得分:3)
最好的方法是编写自定义setter,以便只有在更改后才更新值:
例如:
- (void)setDurationMinutes:(NSNumber *)minutes
{
if (![minutes isEqual:self.durationMinutes])
{
_durationMinutes = minutes;
self.endDate = [self.startDate dateByAddingTimeInterval:minutes * 60];
}
}
- (void)setEndDate:(NSDate *)date
{
if (![_endDate isEqualToDate:date])
{
_endDate = date;
self.durationMinutes = [date timeIntervalSinceDate:self.startDate] / 60;
}
}
现在,当您将分钟设置为其他值时,它将更新并设置结束日期。结束日期将不同,因此它将更新并设置持续时间。但是,这次持续时间将是相同的(因为它是先前设置的),并且它不会再尝试设置自己或结束日期。
它还可以使您的代码保持良好和清洁,并清楚地了解什么以及何时更改。
答案 2 :(得分:1)
将所有三种方法合并为一种方法。
- (void)updateEndDate:(NSDate *)end
startDate:(NSDate *)start
duration:(NSNumber *)duration
{
... insert your update logic here
[self willChangeValueForKey:@"startDate"];
[self willChangeValueForKey:@"endDate"];
[self willChangeValueForKey:@"duration"];
_endDate = end;
_startDate = start;
_duration = duration;
[self didChangeValueForKey:@"duration"];
[self didChangeValueForKey:@"endDate"];
[self didChangeValueForKey:@"startDate"];
}
在你的settors中调用该方法
-(void)setStartDate:(NSDate *)start
{
[self updateEndDate:self.endDate startDate:start duration:self.duration];
}
KVO合规性要求您指定手动发送属性通知
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey
{
BOOL automatic = NO;
NSArray * manualKeys = @[@"endDate", @"startDate", @"duration"];
if ([manualKeys containsObject:theKey])
{
automatic = NO;
}
else
{
automatic = [super automaticallyNotifiesObserversForKey:theKey];
}
return automatic;
}
答案 3 :(得分:0)
最后,事实证明我正在与系统作斗争。我现在计算持续时间值,并使用IBActions对变化采取行动。
- (IBAction)changedEndDate:(id)sender
if ( [_occurrence.endDate timeIntervalSinceDate:_occurrence.startDate] < 0 )
_occurrence.startDate = _occurrence.endDate;
long duration = ( [_occurrence.endDate timeIntervalSinceDate:_occurrence.startDate] ) / 60;
[self.durationHoursTextField setStringValue:[NSString stringWithFormat:@"%ld",duration/60]];
[self.durationMinutesTextField setStringValue:[NSString stringWithFormat:@"%ld",duration%60]];
}
- (IBAction)changedDurationOrStartDate:(id)sender
{
long durH = [self.durationHoursTextField integerValue];
long durM = [self.durationMinutesTextField integerValue];
if ( durH < 0 )
{
durH = 0;
[self.durationHoursTextField setStringValue:@"0"];
}
if ( durM < 0 )
{
durM = 0;
[self.durationMinutesTextField setStringValue:@"0"];
}
long duration = durH * 3600 + durM * 60;
_occurrence.endDate = [_occurrence.startDate dateByAddingTimeInterval:duration];
}