MJQZ1347 MJQZ1347 - 6 months ago 69
iOS Question

How to query for String AND NSDate property?

I am facing an odd error with my code:

if let date = self.messages.last?.date {
let newMessages = self.realm.objects(Message).filter("chatId == '\(self.chatId!)' AND date > \(date)")

This outputs the error:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse the format string "chatId = 'oSgUGWH9fWURmBh5NQZK2POpxdI3yEdl7PrPzAU33l7cVFIpzR38otF3' AND date > 2016-07-17 10:56:07 +0000"'

What am I doing wrong?


it works:

let predicate = NSPredicate(format: "chatId = %@ AND date > %@", self.chatId!, date)
newMessages = self.realm.objects(Message).filter(predicate)

But why doesn't the first solution work?


If you want to filter an array using a predicate, you need to pass a predicate and not just a string literal as the argument, and also use the method filteredArrayUsingPredicate(_:).

Why "chatId == '\(self.chatId!)' AND date > \(date)" doesn't work is that the compiler interprets this as a string literal - and not a predicate as you've created in your other example:

NSPredicate(format: "chatId = %@ AND date > %@", self.chatId!, date)

The fix is to either instantiate an NSPredicate as you've done in your edit, and pass that value to filteredArrayUsingPredicate(:_) or just move the instantiation to inside the method:

newMessages = self.realm.objects(Message).filteredArrayUsingPredicate(NSPredicate(format: "chatId = %@ AND date > %@", self.chatId!, date))

If you want to use this method, the array needs to be an NSArray, and the objects in the array need to be KVC compliant, so you're better off in Swift with using the filter(_:) method as such:

let newMessages = self.realm.objects(Message).filter({ $0.chatId == self.chatId! && $0.date.compare(date) == NSComparisonResult.OrderedDescending })