When I execute this code:
CKDatabase *publicDatabase = [[CKContainer defaultContainer] publicCloudDatabase];
CKRecordID *recordID = [[CKRecordID alloc] initWithRecordName: #"95263874-C860-4190-A2BB-08B3E652B7AA"];
NSPredicate *predicate = [NSPredicate predicateWithFormat: #"%K == %#", #"recordID", [[CKReference alloc] initWithRecordID: recordID action: CKReferenceActionNone]];
CKQuery *query = [[CKQuery alloc] initWithRecordType: #"Case" predicate: predicate];
[publicDatabase performQuery: query inZoneWithID: nil completionHandler: ^(NSArray *results, NSError *error) {
if (error) {
NSLog(#"Error = %#", error);
} else {
NSLog(#"Success");
}
}];
I get this error:
<CKError 0x618000042670: "Server Rejected Request" (15/2000); server message = "Internal server error"; uuid = 122AB9AA-6949-442D-B9D7-736A5B7D2EE5; container ID = "iCloud.net.xxxxxxx">
However, if I change the predicate to this:
NSPredicate *predicate = [NSPredicate predicateWithFormat: #"PatientName = %# ", #"Doe, John"];
The retrieve works correctly. I have verified that John Doe has record name that I am searching for. I have also tried toggling the iCloud "Capability" in the project settings. I have spent hours and hours on this issue and have tried many variations. Nothing works!
Make sure that you've marked Record ID as queryable for this record type in the CloudKit Dashboard.
Select your record type and click on "Metadata Indexes". Check the Query checkbox next to the Record ID field and this error should go away.
Aside from that, rmaddy's answer is right- if you're just trying to fetch a record by its identifier you should use CKFetchRecordsOperation instead of a query.
Related
Anyone know what could be causing this error which is returned in the query block below:
<CKError 0x7f8d5ba27a10: "Internal Error" (1/4000); "Couldn't send a valid signature">
Here is my code snippet:
CKContainer *container = [CKContainer defaultContainer];
CKDatabase *publicDatabase = [container publicCloudDatabase];
//CKDatabase *publicDatabase = [[CKContainer containerWithIdentifier:container] publicCloudDatabase];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"doctorName = %#", #"Dr. Harry White"];
CKQuery *query = [[CKQuery alloc] initWithRecordType:#"WellnessTest" predicate:predicate];
[publicDatabase performQuery:query inZoneWithID:nil completionHandler:^(NSArray *results, NSError *error)
{
if (error)
{
// Error handling for failed fetch from public database
NSLog(#"ERROR: %#", error.description);
}
else
{
// Display the fetched records
NSLog(#"Results: %#", results.description);
}
}];
On the iPhone/iPad simulator go to Settings > iCloud and then log in using your Apple ID.
If you're testing your app against CloudKit's Production environment, you may still have this error even if you have signed into iCloud on the simulator. In this case, running your app on a device would fix the error.
I have a method for destroying outdated NSManagedObjects called messages:
+ (void)syncMessagesByIDs:(NSArray *)messageIDs toGroup:(Group *)group context:(NSManagedObjectContext *)context
{
// This is getting all the Messages that still have a relationship to this Group but
// are not in our passed in set of messages and therefor should be removed
// from the Group.
NSPredicate *searchTerm = [NSPredicate predicateWithFormat:#"(%# IN %K) && NOT (%K in %#)", group, #"groups", #"id_number", messageIDs];
NSArray *results = [Message fetchManyWithPredicate:searchTerm context:context];
for (Message *message in results) {
DLog(#"message.groups %d", message.groups.count);
[message removeGroupsObject:group];
if (message.groups.count == 0) {
[context deleteObject:message];
}
}
}
+ (NSArray *)fetchManyWithPredicate:(NSPredicate *)predicate context:(NSManagedObjectContext *)context
{
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
fetchRequest.entity = [NSEntityDescription entityForName:NSStringFromClass(self) inManagedObjectContext:context];
fetchRequest.predicate = predicate;
fetchRequest.returnsObjectsAsFaults = NO;
NSArray *results = nil;
NSError *error = nil;
results = [context executeFetchRequest:fetchRequest error:&error];
if (error) {
// TODO: Handle error.
}
[fetchRequest release];
return results;
}
Oddly, I have results returned for my fetch. This implies that there are a set of messages that have a relationship to the group which I used for the query BUT do not have an id_number in the array of messageIDs.
However, when I print message.groups from the console I get 0x1f83c740 as the address of the group that matches the group in my query, but the group in my query has an address of 0x1fe99db0, two different addresses.
Because the addresses of the group in my query and the group in the relationship are different my call to [message removeGroupsObject:group] does nothing.
Why could this be happening?
More Info:
If it helps, this call is made in a background thread with a context of NSPrivateQueueConcurrencyType.
The following code also returns a group with a different address than both of the other groups previously shown.
searchTerm = [NSPredicate predicateWithFormat:#"SELF == %#", group];
NSArray *groupResults = [RDGroup fetchManyWithPredicate:searchTerm context:context];
DLog(#"groupsResults: %#", groupResults);
I'm getting the same group with a different address every time.
Wups! I looked down the call stack and just realized my Group entity was never created in the thread of the context I'm using for the fetch request. I needed to pass in the objectID of the Group and create a new Group in the correct context.
I'm curious to why an exception wasn't thrown for accessing an entity outside of the context that owns it though.
Hope this helps anyone else in the future!
Database stucture image.
Get country with predicate active = 1 in debuger watch condition where zactive = 1 it's ok.
In next view controller get sub-objects country.regions but request in debuger got only relationships condition. How send there active = 1 condition for sub-objects? And same way for region.items.
Got some ideas:
Filter result from country.regions but query will remain the same
Build relationships myself
You can create a fetch request with a predicate, and you can use the country object in your predicate. Example:
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"Region"];
request.predicate = [NSPredicate predicateWithFormat:
#"country = %# AND active = 1", country];
NSError *error;
NSArray *activeRegions = [managedObjectContext executeFetchRequest:request
error:&error];
So here's the deal:
// A. Inserting
Item *item = (Item *)[NSEntityDescription insertNewObjectForEntityForName:#"Item" inManagedObjectContext:managedObjectContext];
NSError *error = nil;
[managedObjectContext save:&error];
..
[item setItemID:#"15"];
[managedObjectContext save:&error];
NSLog(#"Error: %#", error); // outputs (null)
// B. Fetching all records
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:#"Item"];
request.returnsObjectsAsFaults = NO;
NSArray *allItems = [managedObjectContext executeFetchRequest:request error:nil];
NSLog(#"All Items: %#", allItems);
Now, this outputs a huge list, containing the previously inserted item:
"<Item: 0x7eb7bc0> (entity: Item; id: 0x7eb71c0 <x-coredata://BC6EB71C-47C0-4445-905D-7D42E6FC611B/Item/p2> ; data: {\n itemID = 15;\n})"
So far so good, but I want to check whether this particular item does exist (I know it may sound strange in this context, but it really makes sense here). However, the predicate I'm using fails (and I don't see why):
// C. Fetching a single record
NSFetchRequest *singleRequest = [[NSFetchRequest alloc] initWithEntityName:#"Item"];
singleRequest.predicate = [NSPredicate predicateWithFormat:#"itemID == %#", #"15"];
NSError *error = nil;
NSArray *results = [managedObjectContext executeFetchRequest:singleRequest error:&error];
NSLog(#"Error: %#", error); // outputs (null) again
NSLog(#"Results: %#", results); // outputs () ...
I don't really understand how to "fix" this.
Here are some other facts:
Using persistent SQLite store with CoreData (pretty much default configuration, not even relationships, just plain key-value in 3 tables).
The itemIDs always are strings
When reopening the app, the second code block, does return an item (= the item inserted in the previous run). Could it be that save: writes to disk asynchronously, and that the NSPredicate only filters items wrote to disk?
Part A happens in a different method, but on the same thread as B and C. C is directly below B and both are placed in the same method.
If you're comparing strings, try this :
#"itemID LIKE %#"
Have a read of this, the section titled 'String Comparisons"
Okay got it. I used #synthesize instead of #dynamic in the particular model's .m-file. Didn't know it would be such a big problem .. :)
For some reason, updating the SQLite-database goes wrong when using #synthesize ..
I have already solved my problem [Blindly] without understanding root cause. But I would rather understand a concept from a professional. So could you please tell me why below identical code one works but another doesn't.
Code 1: Doesn't work
//Above code omitted...
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"gender == m"]; //NOTICE HERE
[request setPredicate:predicate];
NSError *error = nil;
self.people = [self.managedObjectContext executeFetchRequest:request error:&error];
//Below code omitted...
Code 2: Does work
//Above code omitted...
NSString *type = #"m";
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"gender == %#",type]; //NOTICE HERE
[request setPredicate:predicate];
NSError *error = nil;
self.people = [self.managedObjectContext executeFetchRequest:request error:&error];
//Below code omitted...
Forgot to tell about what error I got, I got SIGABRT on below line, When I executed Code 1.
self.people = [self.managedObjectContext executeFetchRequest:request error:&error];
And one more thing, in GCC error was it cannot format predicate because of "gender == m".
Enlighten me!!
Thanks
See the predicate programming guide (heading "Literals"). You can use literals in your string but you have to enclose them in quotes, so
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"gender == 'm'"];
Would have worked. When predicateWithFormat adds in the argument, it knows it is a string. When you just have m in there, it doesn't know what to do with it, hence the error.
example with swift
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
let fetchRequest = NSFetchRequest(entityName:"Words")
fetchRequest.predicate = NSPredicate(format: "letter == '\(letter)'")
var error: NSError?
let fetchedResults =
managedContext.executeFetchRequest(fetchRequest,
error: &error) as? [NSManagedObject]
if let results = fetchedResults {
println(results)
} else {
println("Could not fetch \(error), \(error!.userInfo)")
}