使用 NSPredicateEditor 过滤一天的最佳方法
Posted
技术标签:
【中文标题】使用 NSPredicateEditor 过滤一天的最佳方法【英文标题】:Best way to filter a day with NSPredicateEditor 【发布时间】:2021-05-03 13:18:22 【问题描述】:有没有人想出一个使用 NSPredicateEditor 按天过滤数据 (CoreData) 的解决方案?这个想法是让用户最方便。标准解决方案是为日期定义 2 个标准:
-
一个代表 >= 一天的开始
另一个
一个 EditorRowTemplate 应该如下所示:
左表达式 = aDate(Core Data 实体的属性)
rightexpression = 日期
然后,应用程序应该将谓词转换为类似于:
"aDate >= '3.5.20210 00:00:00' AND aDate <= '3.5.20210 23:59:59'".
当然,它应该取用户在行模板中输入的日期的值。
我想,闭包是一种方法。可以这么说,以编程方式创建 NSPredicate。 但是如何在 NSExpression 中使用它并从输入中获取日期呢?
所需的行模板应如下所示:
【问题讨论】:
NSPredicateEditorRowTemplate
子类怎么样?
是的,这是我的方法。但我正在努力创建一个模板视图,保留 2 个输入字段。在 ObjectiveC 下,您可以操作模板的视图。现在 templateViews() 只是一个 getter 函数。
你想要一行有两个日期还是想要一行有一个日期和一个谓词有两个日期?
我想要一行有 2 个可编辑的日期,以便我可以设置日期
问题是“如何按天过滤”还是“如何实现之间”?您是如何在 Objective-C 中操作模板的视图的?
【参考方案1】:
行模板可以转换predicate(withSubpredicates:)
中的谓词,无需其他覆盖。在 IB 中,正确的表达式是 Dates。
override func predicate(withSubpredicates subpredicates: [NSPredicate]?) -> NSPredicate
// call super to get the predicate, for example aDate == '3.5.20210 14:03:53'
let predicate = super.predicate(withSubpredicates: subpredicates)
// convert the predicate to aDate >= '3.5.2021 00:00:00' AND aDate < '4.5.2021 00:00:00'
var newPredicate = predicate
if let comparisonPredicate = predicate as? NSComparisonPredicate,
let predicateDate = comparisonPredicate.rightExpression.constantValue as? Date
let keyPath = comparisonPredicate.leftExpression.keyPath
var components = Calendar.current.dateComponents([.year, .month, .day], from: predicateDate)
components.hour = 0
components.minute = 0
components.second = 0
components.calendar = NSCalendar.current
switch comparisonPredicate.predicateOperatorType
case .lessThan:
// aDate < '3.5.2021 00:00:00'
let date = components.date! as NSDate
newPredicate = NSPredicate(format: "%K < %@", keyPath,date)
case .lessThanOrEqualTo:
// aDate < '4.5.2021 00:00:00'
components.day = components.day! + 1
let date = components.date! as NSDate
newPredicate = NSPredicate(format: "%K < %@", keyPath,date)
case .greaterThan:
// aDate >= '4.5.2021 00:00:00'
components.day = components.day! + 1
let date = components.date! as NSDate
newPredicate = NSPredicate(format: "%K >= %@", keyPath,date)
case .greaterThanOrEqualTo:
// aDate >= '3.5.2021 00:00:00'
let date = components.date! as NSDate
newPredicate = NSPredicate(format: "%K >= %@", keyPath,date)
case .equalTo:
// aDate >= '3.5.2021 00:00:00' AND aDate < '4.5.2021 00:00:00'
let startDate = components.date! as NSDate
components.day = components.day! + 1
let endDate = components.date! as NSDate
newPredicate = NSPredicate(format: "%K >= %@ AND %K < %@", keyPath, startDate, keyPath, endDate)
case .notEqualTo:
// NOT (aDate >= '3.5.2021 00:00:00' AND aDate < '4.5.2021 00:00:00')
let startDate = components.date! as NSDate
components.day = components.day! + 1
let endDate = components.date! as NSDate
newPredicate = NSPredicate(format: "NOT (%K >= %@ AND %K < %@)", keyPath, startDate, keyPath, endDate)
default:
newPredicate = predicate
return newPredicate
【讨论】:
【参考方案2】:感谢 Willeke 的回答,我得以解决。我想让你参与整个解决方案。
-
创建自定义类CustomRowTemplate:NSPredicateEditorRowTemplate
覆盖 func 谓词,请参见上面 Willeke 的代码。这可以访问您要过滤的日期
它会创建带有当天日期/时间范围的谓词。
override func predicate(withSubpredicates subpredicates: [NSPredicate]?) -> NSPredicate
在属性检查器中,对于 predicateEditor ,为 keypath 和 date 创建一个新的 Rowtemplate。 然后将其类更改为 CustomRowTemplate
就是这样。
【讨论】:
以上是关于使用 NSPredicateEditor 过滤一天的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章
使用 NSPredicateEditor 编辑 NSPredicate
使用 NSPredicateEditor,有没有办法免费获得所有 Finder 搜索类别?