CoreData:为Fetched Results Controller的查询自定义排序描述符
CoreData查询自定义排序:精确匹配优先展示
要实现精确匹配结果排在最前面,后续展示包含搜索字符串的内容,这里提供两种适配Fetched Results Controller的可行方案,无需在查询完成后再处理数据:
方案一:自定义比较器排序(内存层面处理)
适合数据量不大的场景,逻辑直观易懂:
var fetch: NSFetchRequest<CoreNote> = CoreNote.fetchRequest() fetch.predicate = NSPredicate(format: "plainText CONTAINS[c] %@", searchString) // 自定义排序逻辑:精确匹配的排前面,同优先级按文本大小写不敏感排序 let sortDescriptor = NSSortDescriptor(key: nil, ascending: true) { obj1, obj2 in guard let note1 = obj1 as? CoreNote, let note2 = obj2 as? CoreNote else { return .orderedAscending } let text1 = note1.plainText ?? "" let text2 = note2.plainText ?? "" let isExactMatch1 = text1.caseInsensitiveCompare(searchString) == .orderedSame let isExactMatch2 = text2.caseInsensitiveCompare(searchString) == .orderedSame if isExactMatch1 && !isExactMatch2 { return .orderedAscending } else if !isExactMatch1 && isExactMatch2 { return .orderedDescending } else { return text1.caseInsensitiveCompare(text2) } } fetch.sortDescriptors = [sortDescriptor]
方案二:表达式排序(数据库层面处理,推荐)
让CoreData在数据库端完成排序,性能更优,适合数据量大的场景:
var fetch: NSFetchRequest<CoreNote> = CoreNote.fetchRequest() fetch.predicate = NSPredicate(format: "plainText CONTAINS[c] %@", searchString) // 1. 构建表达式:给精确匹配的结果标记优先级1,仅包含的标记0 let compareExpr = NSExpression(forFunction: "caseInsensitiveCompare:", arguments: [ NSExpression(forKeyPath: "plainText"), NSExpression(forConstantValue: searchString) ]) let priorityExpr = NSExpression(forFunction: "if:then:else:", arguments: [ NSExpression(forFunction: "isEqualTo:", arguments: [compareExpr, NSExpression(forConstantValue: NSNumber(value: ComparisonResult.orderedSame.rawValue))]), NSExpression(forConstantValue: 1), NSExpression(forConstantValue: 0) ]) // 2. 先按优先级降序(1在前),再按文本大小写不敏感排序 let prioritySort = NSSortDescriptor(key: nil, ascending: false, expression: priorityExpr) let textSort = NSSortDescriptor(key: "plainText", ascending: true, selector: #selector(NSString.caseInsensitiveCompare(_:))) fetch.sortDescriptors = [prioritySort, textSort]
关键说明
- 方案二的性能远优于方案一,因为排序操作在数据库层面完成,无需将所有数据加载到内存再处理。
- 代码中处理了
plainText为空的情况,避免空值引发崩溃。
内容的提问来源于stack exchange,提问作者FE_Tech
相关产品推荐
相关产品推荐

