CloudKit Query Value Limit Error - nspredicate

I have a query with a predicate in which I want to see if any values inside an array are contained in a CKRecord on CloudKit, but when I execute the query I get an error saying "Query filter exceeds the limit of values: 250 for container"
Is there another way to query my array? It has 500 objects in it, but it's dynamic so depending on the user it could be a lot less or a lot more.
CKDatabase *publicDatabase = [[CKContainer defaultContainer] publicCloudDatabase];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"PhoneNumber == %#", numbers1];
CKQuery *query = [[CKQuery alloc] initWithRecordType:#"PhoneNumbers" predicate:predicate];
[publicDatabase performQuery:query inZoneWithID:nil completionHandler:^(NSArray *results, NSError *error) {
if (error) {
NSLog(#"%#", error);
}
else {
NSLog(#"%#", results);
}
}];

Related

PFUser Query Contraint

This is my current query:
[PFQuery *userQuery = [PFUser query];
[userQuery whereKey:#"phone" containedIn:phones];
[userQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
self.contactsWithApp = objects;
[self.tableView reloadData];
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
I am searching for users according to an array composed of phone number strings. The key 'phone' in my User class contains a phone number string for each user. Why is this not working?
Try using this instead. This is assuming that the class you are querying in Parse is called User.
Replace your line of:
PFQuery *userQuery = [PFUser query];
With this:
PFQuery *userQuery = [PFQuery queryWithClassName:#"_User"];
Final code:
PFQuery *userQuery = [PFQuery queryWithClassName:#"_User"];
[userQuery whereKey:#"phone" containedIn:phones];
[userQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
self.contactsWithApp = objects;
[self.tableView reloadData];
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
I'm pretty sure that this question isn't actual anymore. But I faced with the same problem and want to share with solution. Most likely that you have got JSON response, and your 'phone' in phones - is NSNumber type. To query from Parse with containedIn: array must be with objects of type NSString.

is it possible to update and save a pfobject from a query using parse?

Is it possible to do this:
PFQuery *query = [PFQuery queryWithClassName:#"GameScore"];
[query whereKey:#"playerName" equalTo:#"Dan Stemkoski"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// THis is the part that isn't working
PFObject *pTeam = objects[0];
[pTeam setObject:#"new team name" forKey:#"team"];
[pTeam saveInBackground];
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
When I update the found query object and save, it is not saved to the server.
Is what I am doing possible and if so what am I doing wrong?
Try the below one, it works for me.
PFObject *pTeam = [PFObject objectWithoutDataWithClassName:"GameScore" objectId: [object[0] objectId]];
[pTeam setObject:#"new team name" forKey:#"team"];
[pTeam saveInBackground];

AFNetworking are not writing a response in variable

I have a problem code with using AFNetworking:
#import "SyncProfile.h"
#import "AFNetworking.h"
#implementation SyncProfile: NSObject
#synthesize delegate = _delegate;
- (BOOL)syncProfile {
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSString *token =[userDefaults objectForKey:#"token"];
int user_id = [userDefaults objectForKey:#"user_id"];
if([token length]) {
self.profileData = [[self sendRequest:#"method.get" token:token withUser:user_id andParameters:#"param1,param2"] valueForKeyPath:#"response"];
NSLog(#"%#", self.profileData);
return YES;
} else
return NO;
}
-(id)sendRequest:(NSString *)apiMethod token:(NSString *)token withUser:(int)user_id andParameters:(NSString *)param {
NSMutableString *apiLink = [NSMutableString stringWithFormat:#"https://domain.com/method/%#?uid=%#&fields=%#&access_token=%#", apiMethod, user_id, param, token];
NSURL *url = [[NSURL alloc] initWithString:apiLink];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(#"%#", JSON);
self.req = JSON;
[self myMethod:JSON];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"Request Failed with Error: %#, %#", error, error.userInfo);
}];
[operation start];
return self.req;
}
- (id)myMethod:(id)data {
NSLog(#"%#",data);
return 0;
}
#end
I need to return a variable with the result AFNetworking back method. But the result is given much later than the method returns. When I use a different method to handle the result, it does not. Tried to use the [operation waitUntilFinished] but nothing has changed.
Result in Xcode Output:
//Return variable from "sync" method
2013-02-26 23:57:29.793 walkwithme[13815:11303] (null)
//Return from AFN response
2013-02-26 23:57:31.063 walkwithme[13815:11303] {response = ({someJSON})}
//Return from MyMethod
2013-02-26 23:57:31.063 walkwithme[13815:11303] {response = ({someJSON})}
You definitely don't want to use any wait methods. What you need to do is have a call back in your success and failure blocks. You can do this the way I showed in this question you could also do something else like message passing. The key thing to realize is you won't be using the typical method return pattern. Reason being with asynchronous methods like this you have no idea when it will finish which is why it uses the block call backs. Like I said you definitely don't want to wait because that could entirely block your application.
EDIT:
I use this code in one of my projects:
Declare method
- (void)postText:(NSString *)text
forUserName:(NSString *)username
ADNDictionary:(NSDictionary *)dictionary
withBlock:(void(^)(NSDictionary *response, NSError *error))block;
Then inside this method I pass those parameters to the network request.
Return values in the block with:
if (block) {
block(responseObject, someError);
}
Then I call it with this:
[[KSADNAPIClient sharedAPI] postText:postText
forUserName:username
ADNDictionary:parameters
withBlock:^(NSDictionary *response, NSError *error)
{
if (error) {
// Deal with error
} else {
// Probably success!
}
}
This way the called method returns it's values to the caller method inside the block. I think about it that it defers the block to the caller.

TWRequest code works but very slow to show?

I'm working with TWrequest to display my twitter lists in a tableview. The following code works. The problem is it is very slow to update the table. I am NSlogging the request response (which happens very quickly), I am also looping through each list and adding the list 'name' to an array (which again, happens very quickly <1s). But for some inexplicable reason, the table takes roughly a further 4 seconds or so to update.
Why is this taking so long for the table to reload? The problem is not parsing the response (because I can see with nslog this happens pretty quick), it's taking a long time to display in the table? Help very much appreciated!
-(IBAction)getLists{
// First, we need to obtain the account instance for the user's Twitter account
ACAccountStore *store = [[ACAccountStore alloc] init];
ACAccountType *twitterAccountType = [store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
// Request permission from the user to access the available Twitter accounts
[store requestAccessToAccountsWithType:twitterAccountType withCompletionHandler:^(BOOL granted, NSError *error) {
if (!granted) {
// The user rejected your request
NSLog(#"User rejected access to the account.");
}
else {
// Grab the available accounts
twitterAccounts = [store accountsWithAccountType:twitterAccountType];
if ([twitterAccounts count] > 0) {
// Use the first account for simplicity
ACAccount *account = [twitterAccounts objectAtIndex:0];
// Now make an authenticated request to our endpoint
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
//[params setObject:#"1" forKey:#"include_entities"];
// The endpoint that we wish to call
NSURL *url = [NSURL URLWithString:#"http://api.twitter.com/1.1/lists/list.json"];
// Build the request with our parameter
TWRequest *request = [[TWRequest alloc] initWithURL:url parameters:params requestMethod:TWRequestMethodGET];
// Attach the account object to this request
[request setAccount:account];
[request performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
if (!responseData) {
// inspect the contents of error
NSLog(#"error = %#", error);
}
else {
NSError *jsonError;
NSArray *timeline = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableLeaves error:&jsonError];
if (timeline) {
// at this point, we have an object that we can parse
NSLog(#"timeline = %#", timeline);
for (NSDictionary *element in timeline) {
NSString *listName = [element valueForKey:#"name"];
[listsArray addObject:listName];
}
[listsTable reloadData];
}
else {
// inspect the contents of jsonError
NSLog(#"jsonerror = %#", jsonError);
}
}
}];
}
}
}];
}
Sorry, just came across this post. If you haven't found a solution yet, hopefully this will help.
I believe that performRequestWithHandler can be called on any thread, so UI changes should be dispatched to the main thread.
dispatch_async(dispatch_get_main_queue(), ^{
//update UI here
});
Or in the case of reloading table data you can use:
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];

Cocoa Core Data: Setting default entity property values?

I know I can set default values either in the datamodel, or in the -awakeFromInsert method of the entity class. For example, to make a "date" property default to the current date:
- (void) awakeFromInsert
{
NSDate *now = [NSDate date];
self.date = now;
}
How though can I make an "idNumber" property default to one greater than the previous object's idNumber?
Thanks, Oli
EDIT: Relevant code for my attempt (now corrected)
- (void) awakeFromInsert
{
self.idNumber = [NSNumber numberWithInt:[self maxIdNumber] + 1];
}
-(int)maxIdNumber{
NSManagedObjectContext *moc = [self managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Flight" inManagedObjectContext:moc];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:entityDescription];
// Set example predicate and sort orderings...
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"idNumber > %#", [NSNumber numberWithInt:0]];
[request setPredicate:predicate];
[request setFetchLimit:1];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"idNumber" ascending:NO];
[request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];
NSError *error;
NSArray *array = [moc executeFetchRequest:request error:&error];
if (array == nil | array.count == 0)
{
return 0;
}
return [[[array objectAtIndex:0] valueForKey:#"idNumber"] intValue];
}
If the maxIdNumber method is called, the new object is added to the table twice!? (but with the correct idNumber). The two entries in the table are linked - editing / removing one also edits / removes the other. For this reason I believe it has something to do with the managed object context. For what its worth, the outcome (two copies) is the same no matter how many times the maxIdNumber method is called in the awakFromNib; even if self.idNumber is just set to [NSNumber numberWithInt:5] and the maxIdNumber method is just called for a throwaway variable.
Any clues??
SOLVED IT!
Ok, the problem of double entry occurs when a fetch request is performed from within the awakeFromInsert method. Quoting from the docs:
You are typically discouraged from performing fetches within an implementation of awakeFromInsert. Although it is allowed, execution of the fetch request can trigger the sending of internal Core Data notifications which may have unwanted side-effects. For example, on Mac OS X, an instance of NSArrayController may end up inserting a new object into its content array twice.
A way to get around it is to use the perfromSelector:withObject:afterDelay method as outlined here (I am only allowed to post one hyperlink :( ):http://www.cocoabuilder.com/archive/cocoa/232606-auto-incrementing-integer-attribute-in-awakefrominsert.html.
My working code is now as follows: (note, I have put the bulk of the fetching code used above into a category to tidy it up a little, this allows me to use the method fetchObjectsForEntityName:withPredicate:withFetchLimit:withSortDescriptors:)
- (void) awakeFromInsert
{
[self performSelector:#selector(setIdNumber) withObject:nil afterDelay:0];
self.date = [NSDate date];
}
-(void)setIdNumber
{
int num = 0;
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"idNumber" ascending:NO];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"idNumber > %#", [NSNumber numberWithInt:0]];
NSArray *array = [[self managedObjectContext] fetchObjectsForEntityName:#"Flight"
withPredicate:predicate
withFetchLimit:0
withSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];
if (array != nil & array.count != 0)
{
num = [[[array objectAtIndex:0] valueForKey:#"idNumber"] intValue];
}
num ++;
[self setIdNumber:[NSNumber numberWithInt:num]];
}
Let me know what you think!
One Approach: Create a fetch request of all instances of your entity with a limit of 1, sorted by idNumber to get the highest number.
Another Approach: Keep the highest idNumber in your store's metadata and keep incrementing it.
There are plenty of arguments for and against either. Ultimately, those are the two most common and the choice is yours.
An easier way to do that is to override the newObject method of NSArrayController:
- (id) newObject
{
id result=[super newObject];
[result setValue: [NSDate date] forKey: #"date"];
return result;
}

Resources