对复合NSPredicate进行一些优先排序

时间:2018-05-28 10:58:52

标签: swift database nspredicate

我有以下数据:

NAME | LAST_NAME | PLACE

Roger - Martins - Miami
Mary - Rogers - Paris
Jack - Smith - Maryland
Alfred - Cooper - Germany

... and many more

我有一个这样的谓词:

let searchPredicateName = NSPredicate(format: Database.Key.Name + " CONTAINS[cd] %@", _searchString)
let searchPredicateLastName = NSPredicate(format: Database.Key.LastName + " CONTAINS[cd] %@", _searchString)
let searchPredicatePlace = NSPredicate(format: Database.Key.Place + " CONTAINS[cd] %@", _searchString)

let finalPredicate = NSCompoundPredicate(orPredicateWithSubpredicates: [searchPredicateTitle, searchPredicateLastName, searchPredicatePlace])

当我搜索例如" Mar"那么我得到的结果将是:

Roger - Martins - Miami
Mary - Rogers - Paris
Jack - Smith - Maryland

结果还可以,但我想先让Mary Rogers。一种选择是单独获取,但我不会有一个NSFetchedResultsController作为数据源,这会影响性能

3 个答案:

答案 0 :(得分:1)

我认为您实际上要寻找的是 NSSortDescriptor。 当您使用 NSFetchedResultsController 时,您的 NSFetchRequest 必须有一个排序描述符 - 这就是您进行排序的时间。

NSPredicate 用于比较。即:您要查找的内容。

fetchRequest.sortDescriptors = [NSSortDescriptor(key: "section", ascending: true),// sort by section key first
                                 NSSortDescriptor(key:  "Name", ascending: true), //continue sorting by first name
                                 NSSortDescriptor(key:  "LastName", ascending: true), //continue sorting by last name.
                                 NSSortDescriptor(key: "Place", ascending: true)] //finally by place.

答案 1 :(得分:1)

在查看了上面 hush-entangle 的评论后,我可以清楚地看到我的答案是完全错误的。我有点太兴奋了,无法开始使用这个网站..您实际上是在搜索字符串位置,可能使用 UISearchController 是吗?在这种情况下,您要对结果进行排序,即:

func sortForString(_ string: String) -> [Person] {
     
   let string = string.lowerCased()

   // searchResultsArray or if you want all just sort the fetched objects
    (fetchedResultsController.fetchedObjects?.sorted(by: { lhs, rhs in
    personInfoString(lhs).range(of: string ).lowerBound < personInfoString(rhs).range(of: string ).lowerBound
})) ?? [Person]()
  }

func personInfoString(_ person: Person) -> NSString {
    (person.first ?? "").appending(person.last ?? "").appending(person.place ?? "").lowercased() as NSString
}

let sorted = sortForString("Mar")

然后显示您排序的字符串。 请注意,如果不包含搜索字符串,则保留原始顺序。

清理可能是

extension Person {
func sortableString() -> NSString {
    (self.first ?? " ").appending(self.last ?? " ").appending(self.place ?? " ").lowercased() as NSString
     }
}


 extension NSFetchedResultsController where ResultType == Person {

    func sortedObjects(for searchString: String) -> [Person] {
         (self.fetchedObjects?.sorted(by: { lhs, rhs in
        lhs.sortableString().range(of: searchString ).lowerBound < rhs.sortableString().range(of: searchString ).lowerBound
         })) ?? [Person]()
    }
}

答案 2 :(得分:0)

我假设您有一些实体 UserMO,其中包含字段 namelastNameplace。另外,我假设您使用的是 UISearchController

要按名称排序,请使用 NSSortDescriptor。我们省略谓词,因为我们最初想要显示所有元素。基于此,我们将编写一个用于创建控制器的函数:

func createFetchedResultsController() -> NSFetchedResultsController<UserMO> {
   let request: NSFetchRequest<UserMO> = UserMO.fetchRequest()
   request.sortDescriptors = [
      NSSortDescriptor(keyPath: \UserMO.name, ascending: true)
   ]
   return NSFetchedResultsController<UserMO>(
      fetchRequest: request, 
      managedObjectContext: context,
      sectionNameKeyPath: nil,
      cacheName: nil)
}

在用户编辑搜索字符串的那一刻,委托方法 updateSearchResults 将被调用。在那里,根据用户输入的内容,我们编辑谓词。您无需更改排序规则。

extension ViewController: UISearchResultsUpdating {

   func updateSearchResults(for searchController: UISearchController) {
      let text = searchController.searchBar.text ?? ""
      let predicate: NSPredicate?
      if text.isEmpty {
         predicate = nil // We want to display all items
      } else {
         predicate = NSCompoundPredicate(orPredicateWithSubpredicates: [
            NSPredicate(format: Database.Key.Name + " CONTAINS[cd] %@", text),
            NSPredicate(format: Database.Key.LastName + " CONTAINS[cd] %@", text),
            NSPredicate(format: Database.Key.Place + " CONTAINS[cd] %@", text),
         ])
      }
      fetchedResultsController.fetchRequest.predicate = predicate
      
      do {
         try fetchedResultsController.performFetch()
      } catch {
         print(error)
      }
   }

}