实际答案很少……所以我最终使用了来自 Dave Delong 的名为DDMathParser的开源评估器,它的工作原理与 NSExpression 非常相似,但使用起来更简单,并且可扩展。
在我的模型中,我将 NSManagedObject 子类化为我的“项目”和“公式”。我添加了每个计算的只读属性,如下所示:
在“MyItem.m”中
// Define dependencies of the calculated value upon other attributes, for KVO. Whenever any of the provided keypaths change, there is a need to recalculate.
+ (NSSet *)keyPathsForValuesAffectingCalculatedValue {
return [NSSet setWithObjects:@"x", @"y", @"z", @"formula.expression", nil];
}
- (double) calculatedValue {
NSError *error = nil;
NSDictionary *s = [NSDictionary dictionaryWithObjectsAndKeys: @(self.x) , @"X", @(self.y) , @"Y", @(self.z), @"Z", nil];
NSNumber *result = [[DDMathEvaluator defaultMathEvaluator] evaluateExpression:self.formula.expression withSubstitutions:s error:&error];
if (error)
NSLog(@"Error calculating value: %@", error);
else
return [result doubleValue];
}
在我的“MyFormula.m”中:
@dynamic expressionParsingError;
+ (NSSet *)keyPathsForValuesAffectingExpression {
return [NSSet setWithObjects:@"formulaString", nil];
}
- (DDExpression *)expression {
NSError *err = nil;
DDExpression *exp = [DDExpression expressionFromString:self.volumeFormula error:&err];
self.expressionParsingError = err;
return err ? nil : exp;
}
我不存储甚至不缓存解析的表达式和计算结果。我只缓存一个错误对象,用于显示和报告错误公式的解析错误。在将其转换为 DDExpression 时,我从 DDMathParser 引擎收到此 NSError。
我可以使这些属性成为模型的适当瞬态属性,但由于性能很好,我认为现在没有必要这样做。我可能会在将来的某个时候重新迭代我的解决方案。
然后,在我的表和算法中,我可以简单地将我的 MacOS-X 应用程序表列绑定到“calculatedValue”属性,它会根据需要自动计算(尽管结果不会被缓存)。
将来,我可以消除对 DDMathParser 的需求,并回到 NSExpression。但是 --- DDMathParser 让我可以做一些很棒的事情,比如在用户编辑公式时立即显示解析错误。我还提供了一个小“沙箱”,用户可以在其中使用假数字测试他们的公式,并在将其应用于数百万个项目之前查看他们的公式是否正常工作。
在我相当旧的 MacBookPro (2009) 上分析 10000 个项目是一种即时性。请记住,基于单元格的表格不会评估整个列 - 只是可见部分。
我希望这有帮助...