NSPredicate 格式问题
NSPredicate Formatting Issue
我正在创建一个 iOS 应用程序,我希望用户能够在其中搜索 UITableView
并根据各种不同的输入显示结果。我正在使用具有多个条件的 NSPredicate 由 "OR" 分隔来执行此操作,但出于某种原因,它仅使用第一个条件和其他条件的 none 进行搜索。
这是我的 NSPredicate 的格式:
let searchPredicate = NSPredicate(format: "(SELF.firstName CONTAINS[c]
%@) OR (SELF.lastName CONTAINS[c] %@) OR (SELF.major CONTAINS[c] %@) OR
(SELF.year CONTAINS[c] %@) OR (SELF.gpa CONTAINS[c] %@)",
searchController.searchBar.text!)
我的参数是 firstName、lastName、major、year 和 gpa。当我在搜索栏中输入除名字以外的任何内容时,没有显示任何结果。但是输入名字确实 return 匹配。为什么会这样?我的 NSPredicate 格式不正确吗?
您的谓词中有五个 %@
格式说明符实例,因此您需要传递五个值。你只过了一个。
您需要重复searchController.searchBar.text!
五次。顺便说一句 - 将其分配给一个安全解包的变量并重复该变量五次。它会减少打字。
if let srch = searchController.searchBar.text {
let searchPredicate = NSPredicate(format: "(SELF.firstName CONTAINS[c] %@) OR
(SELF.lastName CONTAINS[c] %@) OR
(SELF.major CONTAINS[c] %@) OR
(SELF.year CONTAINS[c] %@) OR
(SELF.gpa CONTAINS[c] %@)", srch, srch, srch, srch, srch)
...
}
未测试,但这应该有效,并且可能是 Swift 的最简单语法,如果您的所有子谓词都相同:
if let text = searchController.searchBar.text {
let myCompondPredicate = NSCompoundPredicate(orPredicateWithSubpredicates: ["firstName", "lastName", "major", "year", "gpa"].map {
NSPredicate(format: "%K CONTAINS[c] %@", [=10=], text)
})
// Do something with myCompondPredicate here..
}
对于像这样的简单、静态的谓词,我会选择原生 Swift 方法:
import Foundation
struct Student {
let firstName: String
let lastName: String
let major: String
let gpa: Double
}
extension Student {
func anyFields(contain searchString: String) -> Bool {
return firstName.contains(searchString)
|| lastName.contains(searchString)
|| major.contains(searchString)
|| String(gpa).contains(searchString)
}
// Alternate implementation:
/*
func anyFields(contain searchString: String) -> Bool {
return [firstName, lastName, major, String(gpa)].contains(where: { field in
field.contains(searchString)
})
} */
}
let matchingStudents = students.filter(Student.anyFields(contain:))
if let text = searchController.searchBar.text, text.characters.count > 0{
var predicates = [NSPredicate]()
predicates.append(NSPredicate(format: "self.firstName CONTAINS[c]",text))
predicates.append(NSPredicate(format: "self.lastName CONTAINS[c]",text))
predicates.append(NSPredicate(format: "self.major CONTAINS[c]",text))
predicates.append(NSPredicate(format: "self.year CONTAINS[c]",text))
predicates.append(NSPredicate(format: "self.gpa CONTAINS[c]",text))
let searchPredicate:NSPredicate = NSCompoundPredicate(orPredicateWithSubpredicates: predicates)
}
我正在创建一个 iOS 应用程序,我希望用户能够在其中搜索 UITableView
并根据各种不同的输入显示结果。我正在使用具有多个条件的 NSPredicate 由 "OR" 分隔来执行此操作,但出于某种原因,它仅使用第一个条件和其他条件的 none 进行搜索。
这是我的 NSPredicate 的格式:
let searchPredicate = NSPredicate(format: "(SELF.firstName CONTAINS[c]
%@) OR (SELF.lastName CONTAINS[c] %@) OR (SELF.major CONTAINS[c] %@) OR
(SELF.year CONTAINS[c] %@) OR (SELF.gpa CONTAINS[c] %@)",
searchController.searchBar.text!)
我的参数是 firstName、lastName、major、year 和 gpa。当我在搜索栏中输入除名字以外的任何内容时,没有显示任何结果。但是输入名字确实 return 匹配。为什么会这样?我的 NSPredicate 格式不正确吗?
您的谓词中有五个 %@
格式说明符实例,因此您需要传递五个值。你只过了一个。
您需要重复searchController.searchBar.text!
五次。顺便说一句 - 将其分配给一个安全解包的变量并重复该变量五次。它会减少打字。
if let srch = searchController.searchBar.text {
let searchPredicate = NSPredicate(format: "(SELF.firstName CONTAINS[c] %@) OR
(SELF.lastName CONTAINS[c] %@) OR
(SELF.major CONTAINS[c] %@) OR
(SELF.year CONTAINS[c] %@) OR
(SELF.gpa CONTAINS[c] %@)", srch, srch, srch, srch, srch)
...
}
未测试,但这应该有效,并且可能是 Swift 的最简单语法,如果您的所有子谓词都相同:
if let text = searchController.searchBar.text {
let myCompondPredicate = NSCompoundPredicate(orPredicateWithSubpredicates: ["firstName", "lastName", "major", "year", "gpa"].map {
NSPredicate(format: "%K CONTAINS[c] %@", [=10=], text)
})
// Do something with myCompondPredicate here..
}
对于像这样的简单、静态的谓词,我会选择原生 Swift 方法:
import Foundation
struct Student {
let firstName: String
let lastName: String
let major: String
let gpa: Double
}
extension Student {
func anyFields(contain searchString: String) -> Bool {
return firstName.contains(searchString)
|| lastName.contains(searchString)
|| major.contains(searchString)
|| String(gpa).contains(searchString)
}
// Alternate implementation:
/*
func anyFields(contain searchString: String) -> Bool {
return [firstName, lastName, major, String(gpa)].contains(where: { field in
field.contains(searchString)
})
} */
}
let matchingStudents = students.filter(Student.anyFields(contain:))
if let text = searchController.searchBar.text, text.characters.count > 0{
var predicates = [NSPredicate]()
predicates.append(NSPredicate(format: "self.firstName CONTAINS[c]",text))
predicates.append(NSPredicate(format: "self.lastName CONTAINS[c]",text))
predicates.append(NSPredicate(format: "self.major CONTAINS[c]",text))
predicates.append(NSPredicate(format: "self.year CONTAINS[c]",text))
predicates.append(NSPredicate(format: "self.gpa CONTAINS[c]",text))
let searchPredicate:NSPredicate = NSCompoundPredicate(orPredicateWithSubpredicates: predicates)
}