NSPredicate: Unable to parse the format string for relationship - swift

I have two entity named "CIUser" and "CICast". "CIUser" entity has an one-to-one relationship with "CICast" named "cast".
CIUser :
-> userId(Int)
-> isLive(bool)
-> name(String)
CICast:
-> castId(Int)
-> lastUpdate(Date)
Now my requirement is to fetch all the users who are currently live and there lastUpdate is less than a calculated date. So I had prepared my fetch request like
let time = //an calculated NSDate object
let fetchRequest = NSFetchRequest(entityName: "CIUser")
fetchRequest.predicate = NSPredicate(format: "isLive == %# AND cast.lastUpdate <= %#", NSNumber(bool: true), time)
But it crash the application throwing *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse the format string "isLive == %# AND cast.lastUpdate <= %#"'
Can anyone help me where I am doing wrong, or what approach should I take. Suggestion will be appreciated.

The problem is that "CAST" is a reserved word in the predicate format
syntax, and the reserved words are case-insensitive. So this conflicts
with your relationship named "cast".
As a workaround, use the %K key path substitution:
fetchRequest.predicate = NSPredicate(format: "isLive == %# AND %K <= %#",
NSNumber(bool: true), "cast.lastUpdate", time)
or rename the relationship. You may want to use the %K expansion
generally to avoid such problems:
fetchRequest.predicate = NSPredicate(format: "%K == %# AND %K <= %#",
"isLive", NSNumber(bool: true),
"cast.lastUpdate", time)
For more information, see Predicate Format String Syntax
in the "Predicate Programming Guide".

Related

Getting "this class is not key value coding-compliant" when trying to perform NSPredicate in Swift 4

Whenever I try and use an NSPredicate it errors out saying:
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<Project.Object 0x7fc805c23770> valueForUndefinedKey:]: this class is not key value coding-compliant for the key happyfacevalue.'
Now I can't figure out why it refuses to work. I even tried initializing the array I want with #objc and it still crashes.
I understand that the filter feature works incredibly easy, but I need to be able to use NSCompoundPredicate. I don't think I can achieve the level of detailed searching with the Filter feature, that I can with an NSCompoundPredicate.
let tempPredStr = model.selectionQueryArray[count + 1] + "==" + model.inputQueryArray[count + 1]
let predicate = NSPredicate(format: tempPredStr, NSNumber(value: false))
arrayOfPredicates.append(predicate)
/*
let predicateIsNumber = NSPredicate(format: "isStringOrNumber == %#", NSNumber(value: false))
let predicateIsEnabled = NSPredicate(format: "isEnabled == %#", NSNumber(value: true))
*/
count = count + 1
}
let andPredicate = NSCompoundPredicate(type: .and, subpredicates: arrayOfPredicates)
let filteredArray = (predicateArray as NSArray).filtered(using: andPredicate)
I want it to just predicate using the pre-built predicates and to produce an array of objects.

NSPredicate in swift for empty string

Swift 4.2 iOS 11.x
Trying to read the records in a iCloud database that have a lineOwner field set, but struggling to create an NSPredicate that works!
This looks ok, but doesn't parse.
let predicate = NSPredicate(format: remoteAttributes.lineOwner + " != %#",0)
I get an invalid predicate error message [and a nasty crash into the bargain]. Spend a couple of hours on this and losing the will to live.
If I print out the database I see this.
You can simply compare to the empty String, "". The %# placeholder represents a String, so the crash happens because you supply an Int to the NSPredicate instead of a String.
You should also use the %K placeholder for variable names instead of appending strings.
let predicate = NSPredicate(format: " %K != %#", remoteAttributes.lineOwner, "")
If you also want to filter out nil values, you can use a compound predicate:
let predicate = NSPredicate(format: " %K != %# AND %K != nil", remoteAttributes.lineOwner, "")

Core Data - why is my NSPredicate not resulting in the correct SQL query?

I have tried both these NSPredicates:
let predicate = NSPredicate(format: “personID == %lld", id)
let predicate = NSPredicate(format: “personID == %d", id)
I enabled SQL logging and saw this at the end of the SQL query:
WHERE t0.ZPERSONID = ?
In variables view, id has a value of Int64(156), but regardless of what I put in place of id, the resulting SQL query has t0.ZPERSONID = ? for its WHERE clause. Because of this, the predicate is useless and I’m getting duplicate record insertions every time. How do I get t0.ZPERSONID = 156?
WHERE t0.ZPERSONID = ?
is (part of) the prepared statement. To see which values the parameters are bound to, set the Core Data debugging level to 3 (compare How to print Core Data debug values?):
-com.apple.CoreData.SQLDebug 3
-com.apple.CoreData.Logging.stderr 1
Also print(predicate) is useful to check the created predicate
for correctness.
In your case the problem is that you pass an NSNumber instance
as argument, but the %lld format expects an Int64.
You can convert the NSNumber to an Int64
let id = NSNumber(value: Int64(156))
let p1 = NSPredicate(format: "personID == %lld", id.int64Value)
print(p1) // personID == 156
or even simpler, use the %# format instead:
let p2 = NSPredicate(format: "personID == %#", id)
print(p2) // personID == 156

CoreData: NSPredicate filter by date

I have a dataset which contains the following date 6/14, 6/15, 6/16, 6/17 and 6/18
I have two predicates
let today = NSDate()
NSPredicate(format: "checked == %# AND dateTime >= %#", NSNumber(bool: false), today)
NSPredicate(format: "checked == %# AND dateTime < %#", NSNumber(bool: false), today)
let say today is 6/16 so according to the first predicate, fetchRequest should pick only 6/16, 6/17 and 6/18 and for second predicate, fetchRequest should only pick 6/14 and 6/15.
But the problem is first predicate pick all the rows and second one return blank.
DataModel
conversion code
Any idea what's going wrong here.
In your model you set the dateTime property as a Date object, but you saved it as a double.
So you have to do:
dateTime = NSDate(dateWithTimeIntervalSinceReferenceDate:Double(activityInfo["eventDateTime‌​"] as! String))
Note, I don't speak Swift, so I don't know if this code could be shorter, but you get the idea.

CKQuery where predicate has reference and not field?

I need to create a CKQuery where the predicate contains a reference of a record, and not a field of the record.
Like this
let query = CKQuery(recordType: "OUP", predicate: NSPredicate(format: "o = %#", "FF4FB4A9-271A-4AF4-B02C-722ABF25BF44")
How do I set o is a CKReference, not field!
I get this error:
Field value type mismatch in query predicate for field 'o'
You can use a CKRecord or CKRecordID, with or without a CKReference, to match relationships.
CKRecord:
let predicate = NSPredicate(format: "artist == %#", artist)
CKRecordID:
let predicate = NSPredicate(format: "artist == %#", artistID)
CKReference with CKRecord:
let recordToMatch = CKReference(record: artist, action: CKReferenceAction.None)
let predicate = NSPredicate(format: "artist == %#", recordToMatch)
CKReference with CKRecordID:
let recordToMatch = CKReference(recordID: artistID, action: CKReferenceAction.None)
let predicate = NSPredicate(format: "artist == %#", recordToMatch)
I found in CKQuery class reference the answer, or at least an example how to use CKReference in CKQuery:
CKReference* recordToMatch = [[CKReference alloc] initWithRecordID:employeeID action:CKReferenceActionNone];
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"employee == %#", recordToMatch];
To match records that link to a different record whose ID you know, create a predicate that matches a field containing a reference object as shown in Listing 1. In the example, the employee field of the record contains a CKReference object that points to another record. When the query executes, a match occurs when the ID in the locally created CKReference object is the same ID found in the specified field of the record.