Why isnt my NSPredicate working? - ios

So I'm new to iOS development and I'm trying to add a predicate to my NSFetchRequest() in order to filter out items located nearby the user's current location. However, it doesnt seem to be working and the NSFetchRequest returns empty.
let fetchRequest = NSFetchRequest()
fetchRequest.predicate = NSPredicate(format: "itemLatitude BETWEEN {%d, %d}", (latitude-10), (latitude+10))
If I remove the predicate the query returns all items so fetch does work, but not the predicate it seems. There's probably something really basic wrong here and I'd really appreciate any help.

try this :
let fetchRequest = NSFetchRequest()
fetchRequest.predicate = NSPredicate(format: "itemLatitude BETWEEN %#", [(latitude-10), (latitude+10)])
For more details on how use BETWEEN comparison see Apple documentation "Basic Comparisons" part.
Otherwise, you can code you predicate like this :
let fetchRequest = NSFetchRequest()
fetchRequest.predicate = NSPredicate(format: "itemLatitude>%f AND itemLatitude<%f", (latitude-10), (latitude+10))

The issue with your predicate seems to be in the string formating, as #vadian mentioned. Replacing %d to %f makes it work. However, I let you here a little tip for debugging this kind of Predicate issues in the future:
NSPredicate's description method will return you the string of the final Predicate being applied.
NSPredicate(format: "itemLatitude BETWEEN {%f, %f}", (latitude-10), (latitude+10)).description
NSPredicate(format: "itemLatitude BETWEEN {%f, %f}", (latitude-10), (latitude+10)).description
shows in a playground
itemLatitude BETWEEN {0, 0}
itemLatitude BETWEEN {13.45, 33.45}
#ben-messaoud-mahmoud's formating seems also appropriate for this predicate:
NSPredicate(format: "itemLatitude BETWEEN %#", [(latitude-10), (latitude+10)]).description
will also have as result:
itemLatitude BETWEEN {13.45, 33.45}
and is a more clear answer.
Cheers!

Related

NSPredicate format issue

My Entity Office have set of File entities. Each File has uuid property. I need to fetch offices where we have any file where UUID is not in set of Strings
I tried to use
let predicate = NSPredicate(format: "NOT (ALL files.uuid IN %#)", uuidSet)
let predicate = NSPredicate(format: "ANY files.uuid NOT IN %#", uuidSet)
let predicate = NSPredicate(format: "ANY NOT files.uuid IN %#", uuidSet)
I always get the error like
exception 'NSInvalidArgumentException', reason: 'Unsupported predicate NOT ALL files.uuid IN {"C0DF0E67-ED8A-4D3B-87A1-E4E7B86967AA"}'
Is there a way to write this Predicate properly? Because right now I only see the solution to load all offices and then iterate through every item.

Predicate with many conditions and one argument

I'm trying to query contacts realm db but I've one query string, do I need to repeat it over in the predicate or there's a better way?
let contactResults = realm.objects(ContactRealm.self).filter("is_Contact == true AND full_name CONTAINS[c] %# OR phone_number_one CONTAINS[c] %# OR phone_number_two CONTAINS[c] %# OR phone_number_three CONTAINS[c] %# OR email_address_one CONTAINS[c] %# OR email_address_two CONTAINS[c] %#", query, query, query, query, query, query).sorted(byKeyPath: "full_name", ascending: true)
also is querying like this considered a bad practice?
update: as suggested by a comment here:
let predicateContact = NSPredicate(format: "is_Contact == true")
let fullname = NSPredicate(format: "full_name CONTAINS[c] %#", query)
let phoneNumber = NSPredicate(format: "phone_number_one CONTAINS[c] %#", query)
let phonenumbertwo = NSPredicate(format: "phone_number_one CONTAINS[c] %#", query)
let email = NSPredicate(format: "phone_number_one CONTAINS[c] %#", query)
let secondEmail = NSPredicate(format: "phone_number_one CONTAINS[c] %#", query)
let compoundOr = NSCompoundPredicate(orPredicateWithSubpredicates: [fullname, phoneNumber, phonenumbertwo, email, secondEmail])
let compound = NSCompoundPredicate(type: .and, subpredicates: [predicateContact, compoundOr])
let contactResults = realm.objects(ContactRealm.self).filter(compound).sorted(byKeyPath: "full_name", ascending: true)
Since your predicates look the same and only show a difference in the name of the attribute, I would suggest to create an array of attribute names. Then, you can create an NSPredicate for each name by looping through the names.
let attributes = ["full_name", "phone_number_one", "phone_number_two", "phone_number_three", "email_address_one", "email_address_two"]
let contactPredicateArray = parameters.map {
NSPredicate("\($0) CONTAINS[c] %#", query)
}
let contactPredicate = NSCompoundPredicate(orPredicateWithSubpredicates: contactPredicateArray)
let isContactPredicte = NSPredicate(format: "is_Contact == %#", true)
let predicate = NSCompoundPredicate(type: .and, subpredicates: [isContactPredicte, contactPredicate])
This way, the code is more flexible because removing or adding single attributes to your predicate can be done very easily by modifying the attributes array. It is also more readable because all attributes are defined in one line and not all over the place.

How to pass the same parameter multiple times in CoreData iOS predicate builder?

I have a UITableView with a UISearchbar that let me filter the data based on the search text from the UISearchbar.
The CoreData table contains 3 attributes
name, notes, date
I want to search the three columns for any occurrence based on the User search text.
So I tried this on:
let searchText = searchText.lowercased()
let query = "name contains[cd] %# OR notes contains[cd] %# OR date contains[cd] %#"
let predicate = NSPredicate(format: query, searchText, searchText, searchText)
Is there any way to pass the same parameter (searchText) one time?
Something like Java string formatter:
let query = "name contains[cd] %1$# OR notes contains[cd] %1$# OR date contains[cd] %1$#"
let predicate = NSPredicate(format: query, searchText)
You can use substitution variables:
let searchText = searchText.lowercased()
let template = NSPredicate(format: "name contains[cd] $SRCH OR notes contains[cd] $SRCH OR date contains[cd] $SRCH")
let subVars = ["SRCH": searchText]
let predicate = template.withSubstitutionVariables(subVars)
See "Creating Predicates using Predicate Templates" in the Apple Documentation.

NSPredicate Exact Match with String

hello I am working on swift. I need to know how can I find results which matches the exact string. Here's my code
let userID: String = String(sender.tag)
// Create a Predicate with mapping to trip_id
let filterByRequest: NSPredicate = NSPredicate(format: "%K.%K CONTAINS[c] %#", "ProductRequest", "user_id", userID)
// Filter your main array with predicate, resulting array will have filtered objects
let filteredArray: [AnyObject] = self.array.filteredArrayUsingPredicate(filterByRequest)
The problem is If user id is 69 it shows results of users whose id is 69, 6, and 9.
I googled but I find some answers closed to my question but they were all in objective C.
Use MATCHES in predicate as following :
let filterByRequest: NSPredicate = NSPredicate(format: "%K.%K MATCHES %#", "ProductRequest", "user_id", userID)
Hope it helps..
To test for exact equality, simply use == instead of CONTAINS:
NSPredicate(format: "%K.%K == %#", ...)
This can also be combined with [c] for case-insensitive equality:
NSPredicate(format: "%K.%K ==[c] %#", ...)

NSPredicate substring in string

I want to show all items where value1 contains value2. I tried this:
let fetchRequest = NSFetchRequest(entityName: "Product")
fetchRequest.predicate = NSPredicate(format: "value1 CONTAINS[cd] value2")
value1, value2 - current object values, it is not variables
But i got error:
Unable to parse the format string
Why it doesn't allow me to do this ?
Try to use this predicate:
let predicate = NSPredicate(format: "value1 CONTAINS[cd] %#", value2)
As were investigated during communication with developer. Issue is in data that is saved to the database. In his case data is saved with quotes ("") and NSPredicate(format: "value1 CONTAINS[cd] %#", value2) is working with errors due to that issue.

Resources