使用 NSPredicate Editor 过滤一天的最佳方式
Best way to filter a day with NSPredicateEditor
有没有人找到使用 NSPredicateEditor 按天过滤数据 ( CoreData ) 的解决方案?这个想法是为了让用户最方便。标准解决方案是为日期定义 2 个标准:
- 一个用于 >= 一天的开始
- 另一个 <= 一天结束时。
一个 EditorRowTemplate 应该看起来像:
left expression = aDate(核心数据实体的属性)
rightexpression = 日期
然后,应用程序应将谓词转换为类似于:
"aDate >= '3.5.20210 00:00:00' AND aDate <= '3.5.20210 23:59:59'".
当然,它应该取用户在行模板中输入的日期的值。
我想,闭包可以是一种方式。也就是说,以编程方式创建 NSPredicate。
但是如何在 NSExpression 中使用它并从输入中获取日期?
所需的行模板应如下所示:
行模板可以转换 predicate(withSubpredicates:)
中的谓词,不需要其他覆盖。在 IB 中,正确的表达式是日期。
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
}
多亏了 Willeke 的回答,我才得以解决。我想让你参与整个解决方案。
- 创建自定义 class CustomRowTemplate: NSPredicateEditorRowTemplate
- 覆盖 func 谓词,参见上面 Willeke 的代码。这可以访问您要过滤的日期
并且它创建了当天范围为 date/time 的谓词。
override func predicate(withSubpredicates subpredicates: [NSPredicate]?) -> NSPredicate
在属性检查器中,为 predicateEditor 为键路径和日期创建一个新的 Rowtemplate。
然后将其 class 更改为 CustomRowTemplate
就这些了。
有没有人找到使用 NSPredicateEditor 按天过滤数据 ( CoreData ) 的解决方案?这个想法是为了让用户最方便。标准解决方案是为日期定义 2 个标准:
- 一个用于 >= 一天的开始
- 另一个 <= 一天结束时。
一个 EditorRowTemplate 应该看起来像:
left expression = aDate(核心数据实体的属性)
rightexpression = 日期
然后,应用程序应将谓词转换为类似于:
"aDate >= '3.5.20210 00:00:00' AND aDate <= '3.5.20210 23:59:59'".
当然,它应该取用户在行模板中输入的日期的值。
我想,闭包可以是一种方式。也就是说,以编程方式创建 NSPredicate。 但是如何在 NSExpression 中使用它并从输入中获取日期?
所需的行模板应如下所示:
行模板可以转换 predicate(withSubpredicates:)
中的谓词,不需要其他覆盖。在 IB 中,正确的表达式是日期。
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
}
多亏了 Willeke 的回答,我才得以解决。我想让你参与整个解决方案。
- 创建自定义 class CustomRowTemplate: NSPredicateEditorRowTemplate
- 覆盖 func 谓词,参见上面 Willeke 的代码。这可以访问您要过滤的日期 并且它创建了当天范围为 date/time 的谓词。
override func predicate(withSubpredicates subpredicates: [NSPredicate]?) -> NSPredicate
在属性检查器中,为 predicateEditor 为键路径和日期创建一个新的 Rowtemplate。 然后将其 class 更改为 CustomRowTemplate
就这些了。