Search code examples
swiftcore-datanscompoundpredicate

How to create NSCompoundPredicate with "empty" predicate


I try to combine more individual predicates into one via NSCompoundPredicate but it may happen that one or more predicates are not constructed because all objects should be retrieved from CoreData entity (so no predicate is actually needed).

if isGenreFilterOn {
    genrePredicate = NSPredicate(format: "genID == \(genreID)")
}
if searchFor != "" {    
    bookPredicate = NSPredicate(format: "bokName CONTAINS[cd] %@", searchFor)
}
let predicate = NSCompoundPredicate(type: .and, subpredicates: [genrePredicate, bookPredicate])

App fails in case the any of the predicates is not constructed. What is the best way to avoid of many if clauses, should I rather construct predicates retrieving all objects from entity or is there any clever way? Thanks.


Solution

  • Instead of creating “empty” predicates you can dynamically build an array containing only the needed predicates:

    var predicates = [NSPredicate]() // Start with empty list.
    if isGenreFilterOn {
        // Add genre predicate:
        predicates.append(NSPredicate(format: "genID == \(genreID)"))
    }
    if !searchFor.isEmpty {
        // Add book predicate:
        predicates.append(NSPredicate(format: "bokName CONTAINS[cd] %@", searchFor))
    }
    // ... more criteria ...
    
    // Combine all predicates:
    let predicate = NSCompoundPredicate(type: .and, subpredicates: predicates)
    

    More optional (or non-optional) criteria can easily be added. This works correctly even if the predicates array is empty.


    Remark: Be careful with string interpolation in predicate format strings.

    NSPredicate(format: "genID == \(genreID)")
    

    is fine if genreID is a number, but can crash at runtime if it is a string and contains any special characters or reserved keywords for predicates.