3

I'm trying to do this with a compound predicate using Cloudkit, but Xcode error says "Unexpected Expression". Anyone know what is wrong with my code? Appreciate any help!

let userRef = CKReference(recordID: userID, action: .None)

    let predicateOne = NSPredicate(format: "recordID IN %@ AND user = %@", postIDs, userRef)
// I need all user post's that match the IDs in the array and where the user ID matches the Id in the reference field for the user.

    let predicateTwo = NSPredicate(format: "recordID IN %@", followIDs)
// Or I want recordID's that match the IDs in this array.
// I want records if either predicate condition is met, or both, which is why I'm using an OrPredicateType.

    let predicate = NSCompoundPredicate(type: NSCompoundPredicateType.OrPredicateType, subpredicates: [predicateOne!, predicateTwo!])
    let query = CKQuery(recordType: "UserPosts", predicate: predicate)
    let queryOp = CKQueryOperation(query: query)
Renee Olson
  • 267
  • 1
  • 15
  • I don't see why those predicates would fail. Can you include the exact error that you're getting? – farktronix Apr 01 '15 at 16:54
  • Are postIDs and followIDs arrays of CKReferences to CKRecordIDs? – Marcus Oct 26 '15 at 21:59
  • @Marcus. Those arrays are the recordIDs and I'm querying the metadata indexes for those recordIDs. The userRef variable is a CKReference. – Renee Olson Oct 26 '15 at 22:54
  • I had a similar predicate that was giving me trouble, I changed it from an array of recordIDs to an array of CKReferences to CKRecordIDs and my predicate started working. Not sure if this helps with your compound predicate, but it could be worth a try. – Marcus Oct 28 '15 at 01:11

1 Answers1

2

There are some rules for using A NSPredicate for CloudKit. For more information see the Apple documentation

What you could try is create the predicate like this:

NSPredicate(format: "recordID IN %@ OR (recordID IN %@ AND user = %@)", followIDs, postIDs, userRef)

But I have bad experience with using predicates with both AND and OR statements in it. It this predicate does not work, then I think the only solution is executing 2 separate queries and then combining the result. You could do that by using the union function from the ExSwift library

Edwin Vermeer
  • 13,017
  • 2
  • 34
  • 58
  • Unfortunately that didn't work, as it gives same error, but thanks for the help. I'll check out that union function you mention. @EdwinVermeer. – Renee Olson Mar 31 '15 at 20:33
  • Do you have a best practice for doing multiple queries? I've been using the queryCompletionBlock from the first query to call another function that contains the next query. And then I'm still not sure what to do about if you get a cursor, where you don't want the first batch of records to process until you run the 2nd query. I've heard about using dependencies. Appreciate any thoughts you have. @EdwinVermeer – Renee Olson Mar 31 '15 at 21:00
  • That's usually how I do it. (call the 2nd from the completion block). When you want to use a cursor to continuously execute a query, then try writing it recursive (if cursor then call self otherwise call 2nd query) You could use promises or futures to streamline this. See https://github.com/Thomvis/BrightFutures or https://github.com/ReactKit/SwiftTask Besides that I of course do all my CloudKit work using https://github.com/evermeer/EVCloudKitDao – Edwin Vermeer Apr 01 '15 at 06:27
  • 1
    CloudKit doesn't allow joins, so a compound predicate with OR will be disallowed (and don't try to get clever with "AND NOT"). You'll have to run two separate queries and join the results yourself. – farktronix Apr 01 '15 at 16:52
  • Thanks for all those resources Edwin. I definitely have had a lot of issues using CloudKit as a new developer and only knowing Swift and not Obj-C, as there's not much documentation out there. I am curious what you found to be most helpful about using EVCloudKitDao, rather then doing it yourself. @Edwin Vermeer – Renee Olson Apr 01 '15 at 23:27
  • The 'killer' feature of EVCloudKitDao is that you don't have to parse from and to CKRecord. You just work with objects. The second top feature is that you can create a 'connection' with a query. You will then get an object array in your app that represents a query. All changes will be merged (from the push notifications). It just makes working with CloudKit a lot easier. – Edwin Vermeer Apr 02 '15 at 06:27