In my app the user is able to add an value with an UISwitch. Once the user has selected the value the, value is uploaded to the current user in parse. When the user gets back to the view where the user selected the value using the UISwitch, i want the UISwitch to be loaded the way the current user selected it last time. But i just cant get it to work.
I use this query, to get the value from the currentUser
PFQuery *query= [PFUser query];
[query whereKey:#"username" equalTo:[[PFUser currentUser]username]];
PFObject *object = [query getFirstObject];
And this is where i want to put the value in.
(void)viewDidAppear:(BOOL)animated; {
[super viewDidAppear:animated];
PFQuery *query= [PFUser query];
[query whereKey:#"username" equalTo:[[PFUser currentUser]username]];
PFObject *object = [query getFirstObject];
NSNumber *logNSNumber = [object valueForKey: #"Active"];
bool switchValue = [logNSNumber boolValue];
BOOL switchValue;
if (switchValue)
{
switchLog.on = TRUE;
legoTextView.hidden = NO;
}
else
{
switchLog.on = FALSE;
lTextView.hidden = YES;
}
}
And this is how i send the boolean value up to parse.
-(IBAction)changeBoolean; {
Boolean switchVaule;
if (switchLog.on)
{
switchVaule = TRUE;
logTextView.hidden = NO;
PFUser *log = [PFUser currentUser];
log[#"Active"] = #YES;
[log saveInBackground];
}
else
{
switchVaule = FALSE;
logTextView.hidden = YES;
PFUser *log = [PFUser currentUser];
log[#"Active"] = #NO;
[log saveInBackground];
}
}
Does any one know how to solve this problem, is this the right way to do this, or am i trying to do this the wrong way? Thx!
There are lots of things that are wrong in your code. For one; you are getting the PFUser object for the current user by querying for it using data from the user object you're already having ([PFUser currentUser]). When you log in, Parse gives you this object automatically, and you don't need to query for it. To store a value in it:
[[PFUser currentUser] setObject:[NSNumber numberWithBool:YES] forKey:#"Active"];
[[PFUser currentUser] saveInBackground];
to get value from it:
[[PFUser curentUser] objectForKey:#"Active"];
In your code, you're not getting the stored value anywhere to use in your switch. One solution:
switchLog.on = [[PFUser curentUser] objectForKey:#"Active"];
You have also, as jrturton points out, lots of typos in your code, and less-than-ideal condition handling. Clean that up and try using the code I provided.
Related
and thank you for your advice!
I am using fetchAllSubscriptionsWithCompletionHandler, and I do see the subscritionID from each CKSubscription after the push notification is sent. How do I retrieve the CKRecord from the subscriptionID?
I do not see the Remote Push Notification from a CKReference that was created. I can see the CKRecord and its related record via CloudKit DashBoard. I do receive a Push Notification from when its parent record is created, but not when the CKReference is created on the child record.
-(void)SubscribeForReference:(CKRecord *)record
{
NSUserDefaults *trackSubscription = [NSUserDefaults standardUserDefaults];
BOOL hasSubscribed = [[NSUserDefaults standardUserDefaults] objectForKey:#"alreadySubscribedForReference"] != nil;
//BOOL hasSubscribed = [trackSubscription objectForKey:#"alreadySubscribedForReference"];
if (hasSubscribed == false) {
//creates a subscription based on a CKReference between two ckrecords
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"sentences == %#", record.recordID];
// 1) subscribe to record creations
CKSubscription *subscriptionRelation =
[[CKSubscription alloc] initWithRecordType:#"RecordTypeName"
predicate:predicate
options:CKSubscriptionOptionsFiresOnRecordCreation | CKSubscriptionOptionsFiresOnRecordUpdate | CKSubscriptionOptionsFiresOnRecordDeletion | CKSubscriptionOptionsFiresOnRecordUpdate];
//http://stackoverflow.com/questions/27371588/cloudkit-notifications
CKNotificationInfo *notificationInfo = [[CKNotificationInfo alloc] init];
// I added this because of apple's documentation
notificationInfo.desiredKeys = #[#"word",#"identifier"];
notificationInfo.alertLocalizationArgs = #[#"word"];
notificationInfo.alertLocalizationKey = #"%1$#";
notificationInfo.shouldBadge = YES;
subscriptionRelation.notificationInfo = notificationInfo;
[self.privateDatabase saveSubscription:subscriptionRelation completionHandler:^(CKSubscription * _Nullable subscription, NSError * _Nullable error) {
if (error == nil) {
[trackSubscription setObject:subscription.subscriptionID forKey:#"alreadySubscribedForReference"];
[trackSubscription synchronize];
}else
NSLog(#"something went wrong with saving the CKSubcription with error...\n%#\n",[error localizedDescription]);
}];
}
else{
NSLog(#"\nSubscribeForReference: ALREADY has subscription: %# set for key 'alreadySubscribedForReference' \n\n ", [trackSubscription objectForKey:#"alreadySubscribedForReference"]);
}
}
The code below is ran when the app is launched, provided there is an Internet connection:
-(void)runWhenAppStarts
{
CKFetchSubscriptionsOperation *fetchSubscriptionsOperation = [CKFetchSubscriptionsOperation fetchAllSubscriptionsOperation];
fetchSubscriptionsOperation.fetchSubscriptionCompletionBlock = ^(NSDictionary *subscriptionsBySubscriptionID, NSError *operationError) {
if (operationError != nil)
{
// error in fetching our subscription
CloudKitErrorLog(__LINE__, NSStringFromSelector(_cmd), operationError);
if (operationError.code == CKErrorNotAuthenticated)
{
// try again after 3 seconds if we don't have a retry hint
//
NSNumber *retryAfter = operationError.userInfo[CKErrorRetryAfterKey] ? : #3;
NSLog(#"Error: %#. Recoverable, retry after %# seconds", [operationError description], retryAfter);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(retryAfter.intValue * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self subscribe];
});
}
}
else
{
if (self.subscribed == NO)
{
// our user defaults says we haven't subscribed yet
//
if (subscriptionsBySubscriptionID != nil && subscriptionsBySubscriptionID.count > 0)
{
// we already have our one CKSubscription registered with the server that we didn't know about
// (not kept track in our NSUserDefaults) from a past app install perhaps,
//
NSLog(#"\nsubscriptionsBySubscriptionID (dictionary) = %#\n",subscriptionsBySubscriptionID);
NSArray *allSubscriptionIDKeys = [subscriptionsBySubscriptionID allKeys];
NSLog(#"\nallSubscriptionIDKeys (array) = %#\n",allSubscriptionIDKeys);
if (allSubscriptionIDKeys != nil)
{
[self updateUserDefaults:allSubscriptionIDKeys[0]];
for (NSString *subscriptions in allSubscriptionIDKeys) {
NSLog(#"subscriptionID: %#\n",subscriptions);
}
}
}
else
{
// no subscriptions found on the server, so subscribe
NSLog(#"...starting subscriptions on server...\n");
[self startSubscriptions];
}
}
else
{
// our user defaults says we have already subscribed, so check if the subscription ID matches ours
//
NSLog(#"...our user defaults says we have already subscribed, with subscriptionsBySubscriptionID = %#\nso check if the subscription ID matches the one already stored in NSUserDefaults...\n",subscriptionsBySubscriptionID);
if (subscriptionsBySubscriptionID != nil && subscriptionsBySubscriptionID.count > 0)
{
// we already have our one CKSubscription registered with the server that
// we didn't know about (not kept track in our NSUserDefaults) from a past app install perhaps,
//
//NSDictionary *subscriptionsBySubscriptionID has a structure of #{key: value} == #{NSString: CKSubscription}
NSArray *allSubscriptionIDKeys = [subscriptionsBySubscriptionID allKeys];//contains the NSString representation of the subscriptionID.
NSArray *allSubscriptionIDVALUES = [subscriptionsBySubscriptionID allValues];// the values are the corresponding CKSubscription objects
for (CKSubscription *values in allSubscriptionIDVALUES) {
NSLog(#"\nCKSubscriptionValue = %#\n",values);
}
NSLog(#"\n...we already have our one CKSubscription registered with the server that..so lets look at allSubscriptionIDKeys =%#.\n\nvalues ...\nallSubscriptionIDVALUES = %#\n\n",allSubscriptionIDKeys,allSubscriptionIDVALUES);
if (allSubscriptionIDKeys != nil)
{
NSString *ourSubscriptionID = [[NSUserDefaults standardUserDefaults] objectForKey:kSubscriptionIDKey];
if (![allSubscriptionIDKeys[0] isEqualToString:ourSubscriptionID])
{
// our subscription ID doesn't match what is on the server, to update our to match
NSLog(#"...our subscription ID doesn't match what is on the server, going to update our NSUserDefaults...\n");
[self updateUserDefaults:allSubscriptionIDKeys[0]];
}
else
{
// they match, no more work here
NSLog(#"...iCloud server already has this subscriptionID, so do nothing.i.e. don't subscribe again..\n");
}
}
}
}
}
};
[self.privateDatabase addOperation:fetchSubscriptionsOperation];
}
When you fetch subscriptions, you don't get a specific record ID. Instead, the subscription's .recordType will tell you the type of record this subscription monitors. Typically, if you have 1,000 users, then you would have 1,000 instances of the record, and each user would create subs to monitor when their instance is modified.
When the subscription is triggered, you'll receive a notification. You can use CKFetchNotificationChangesOperation to retrieve the notifications. Each notif includes a .recordID value that tells you specifically which record changed and caused the subscription to fire.
You're currently querying the subs to make sure the user has properly subscribed. Next, you also need to query the notifications with CKFetchNotificationChangesOperation to see which records have been updated when the subscription(s) fired.
You may extract RecordID from the predicate of subscription.
For example - if subscription predicate was:
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"(author == %#)", artistRecordID];
where artistRecordID is reference to another recordType - then you may extract RecordID in the following way:
[publicDatabase fetchAllSubscriptionsWithCompletionHandler:^(NSArray<CKSubscription *> *subscriptions, NSError *error){
if(error){
// handle error
}
else {
[subscriptions indexOfObjectPassingTest:^BOOL(CKSubscription * obj, NSUInteger idx, BOOL *stop){
if ([obj.predicate isKindOfClass:[NSComparisonPredicate class]]) {
NSComparisonPredicate *p2a = (NSComparisonPredicate *)obj.predicate;
NSExpression *e6 = p2a.rightExpression;
CKReference* ref=e6.constantValue;
// you may extract RecordID here from ref
// for example - to compare against another RecordID:
if([ref.recordID.recordName isEqualToString:artistRecordID.recordID.recordName]){
*stop=YES;
return YES;
}
}
return NO;
}];
}
}];
I have a code like that
if ([dataArray valueForKey:#"success"]) {
[self.feedsArray addObjectsFromArray:dataArray];
NSLog(#"self.feedsArray: %#",self.feedsArray);
} else {
NSLog(#"no feed found ");
}
dataArray is a NSMutableArray which ultimately contains a JSON Dictionary.
but I am getting the same console output independent of success either TRUE or FALSE, but my console output is always same.my console output is:
for FALSE or NO:
self.feedsArray: (
{
action = register;
message = "Invalid parameters";
success = 0;
}
)
and for TRUE or YES:
self.feedsArray: (
{
action = register;
message = "valid parameters";
success = 1;
}
)
in both cases if part is executed.
in NSUserDefaults there is a method boolForKey but how to do this in case of NSMutableArray.
You need to read the fine print for [NSArray valueForKey:], specifically:
Returns an array containing the results of invoking valueForKey: using
key on each of the array's objects.
and:
The returned array contains NSNull elements for each object that
returns nil.
So if the array contains, say, 3 objects and none of them have a success key then you will get an array of 3 NSNull objects returned.
Therefore the if statement will fire whenever dataArray is non-empty, which is obviously not what you intended.
You should check the contents of the returned array:
BOOL succeeded = NO;
NSArray *results = [dataArray valueForKey:#"success"];
for (NSObject *obj in results) {
succeeded = [obj isKindOfClass:[NSNumber class]] && [(NSNumber *)obj boolValue];
if (succeeded)
break;
}
if (succeeded) {
[self.feedsArray addObjectsFromArray:dataArray];
NSLog(#"self.feedsArray: %#",self.feedsArray);
} else {
NSLog(#"no feed found ");
}
You can do this in simple way:
What i see in your response json value is, you have dictionary in dataArray at index 0
NSMutableDictionary *responseDict = [dataArray objectAtIndex:0];
if([[responseDict objectForKey:#"success"] boolValue])
{
NSLog(#"Success: 1");
}
{
NSLog(#"Success: 0");
}
Use index instead of key for an array.
NSDictionary dictionary = (NSDictionary *)dataArray[0];
if ([(NSNumber *)[dictionary objectForKey:#"success"] boolValue]) {
// ...
}
otherwise use if([[[dataArray objectAtIndex:0] valueForKey:#"success"] isEqualToString:#"1"])
An array does not store keys, the only way to access items in an array is by index.
You should be using an NSDictionary/NSMutableDictionary instead. If you want to use a bool store it as a NSNumber, [NSNumber numberWithBool:YES] and then use the instance method valueForBool to read it back.
Try this
if ([[dataArray valueForKey:#"success"]isEqualToString:#"1"]) {
[self.feedsArray addObjectsFromArray:dataArray];
NSLog(#"self.feedsArray: %#",self.feedsArray);
}
else {
NSLog(#"no feed found ");
}
It 'll work out.
use this if you want bool value
if([[dataArray valueForKey:#"success"] boolValue])
{
//i.e success is true
}
if response contains array of dictionaries then we can use loop and check condition,
here i is index variable of array,
if([[[dataArray objectAtIndex:i] objectForKey:#"success"] boolValue])
{
// success is true ,
}
Replace you code line
if ([dataArray valueForKey:#"success"]) {
}
with
if ([[dataArray valueForKey:#"success"] integerValue]) {
}
Hope it will work for you.
its working with replacing the line with
if ([[[dataArray objectAtIndex:0] valueForKey:#"success"] boolValue])
I am crashing at runtime when i pop last element from NSMuttable array.I am getting all element fine but when i acess last element it will give error.
-(id)popOperand{
id operandObject = [self.operandStack lastObject];
if(operandObject) [self.operandStack removeLastObject];
return operandObject;
}
For eg:- if in my stack i have "8"(Its NSNumber object) "+"(Its NSString object) 2(Its NSnumber Object).
NSNumber *rightOperand = [self popOperand];
NSString *operation = [self popOperand];
NSNumber *leftOperand = [self popOperand];//when i acess 8 it shows empty array other element is getting fine;
My question is why i am not able to get last object while this function is working fine for other elememts.
EDIT : At run time when after poping 2 it show stack( 8 +) but after i poped + it show stack() empty.But The "leftOperand" is not getting value. I am not using ARC.
Please ellaborate it.
Thanks.
If you aren't using ARC then you have memory management issues:
- (id)popOperand
{
id operandObject = [self.operandStack lastObject]; // Still retained by operandStack
if(operandObject) [self.operandStack removeLastObject];// Released by operandStack
return operandObject; // Could be dealloc'd any time now!
}
Try this version, which returns a retain'd and autorelease'd object, which conforms to the naming convention of the method:
- (id)popOperand
{
id obj = nil;
if ([self.operandStack count] > 0)
{
id obj = [[[self.operandStack lastObject] retain] autorelease];
[self.operandStack removeLastObject];
}
return obj;
}
I'm trying to implement a searchable tableview in my app, where when someone can search a location and get results. It looks something like this:
I'm getting my source from genomes.com which gives more then just cities, it also has parks, buildings, counties, etc. I want to just show locations which are cities.
The data is a JSON file which is parsed by JSONKit. The whole file comes in (maximum 20 objects) and then the searchable table view shows it. I'm not sure if I should parse the JSON file differently, or if I should make the table view show only the results needed. (Performance in this case is not an issue.). The JSON file gets converted to an NSArray.
Here is part of the array:
{
adminCode1 = MA;
adminCode2 = 027;
adminName1 = Massachusetts;
adminName2 = "Worcester County";
adminName3 = "";
adminName4 = "";
adminName5 = "";
continentCode = NA;
countryCode = US;
countryName = "United States";
elevation = 178;
fcl = A;
fclName = "country, state, region,...";
fcode = ADMD;
fcodeName = "administrative division";
geonameId = 4929431;
lat = "42.2000939";
lng = "-71.8495163";
name = "Town of Auburn";
population = 0;
score = "53.40083694458008";
timezone = {
dstOffset = "-4";
gmtOffset = "-5";
timeZoneId = "America/New_York";
};
toponymName = "Town of Auburn";
},
What I want to do is if the "fcl" (seen in the array) is equal to P, then I want it to show that in the table view. If the "fcl" is some other character, then I don't want it to be seen in the table view. I'm pretty sure that an if statement can do that, but I don't know how to get it so that it filters part of it.
Any help would be appreciated! Thanks
EDIT: As of now, this is the code to search:
- (void)delayedSearch:(NSString*)searchString
{
[self.geoNamesSearch cancel];
[self.geoNamesSearch search:searchString
maxRows:20
startRow:0
language:nil];
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
self.searchDisplayController.searchBar.prompt = NSLocalizedStringFromTable(#"ILGEONAMES_SEARCHING", #"ILGeoNames", #"");
[self.searchResults removeAllObjects];
// Delay the search 1 second to minimize outstanding requests
[NSObject cancelPreviousPerformRequestsWithTarget:self];
[self performSelector:#selector(delayedSearch:) withObject:searchString afterDelay:0];
return YES;
}
Your question is basically, how do you filter your array from a search bar string? If so, you can detect when the text changes via UISearchBarDelegate and then go through your array copying those objects that contain the string you are looking for, i.e.
This is the delegate method you want: searchBar:textDidChange:.
[filterArray removeAllObjects];
for(int i = 0; i < [normalArray count]; i++){
NSRange textRange;
textRange =[[[[normalArray objectAtIndex:i] objectForKey:#"name"] lowercaseString] rangeOfString:[searchBarString lowercaseString]];
//I wasn't sure which objectForKey: string you were looking for, just replace the one you want to filter.
if(textRange.location != NSNotFound)
{
[filterArray addObject:[normalArray objectAtIndex:i]];
}
}
filterTableView = YES;
[tableView reloadData];
Note the filterTableView bool value, this is so your tableView knows either to load normally or the filtered version you just made. You implement this in:
tableView:numberOfRowsInSection: //For number of rows.
tableView:cellForRowAtIndexPath: //For the content of the cells.
Hope this is what you were looking for.
NSMutableArray* filtered = [[NSMutableArray alloc] autorelease];
for (int i=0;i<[data count];i++)
{
NSDictionary* item=[data objectAtIndex:i];
if (#"P" == [item objectForKey:#"fcl"] )
{
[filtered addObject:item];
}
}
So every time the search field changes, you will compute a new array, and then reload your tableview. The number of rows will be the numbers of rows in your filtered array.
To compute the new array, you can do this (assuming an array of dictionaries):
NSString *searchString; // from the search field
NSMutableArray *array = [NSMutableArray arrayWithCapacity:[origArray count]];
for(NSDictionary *dict in origArray) {
NSString *val = [dict objectForKey:#"fcl"];
if([val length] >= searchString) {
NSString subString = [val substringToIndex:[searchString length]];
if([subString isEqualToString:val]) [array addObject:dict];
}
}
Each cell then will get its values from the new array.
Just put your json in a NSDictionary and simply do something like :
if ([[yourJson objectForKey:#"fcl"] stringValue] == #"A")
//doSomething
I need to set a text of a label if some particular conditions are true (don't pay attention to them because that part of code is correct). It should be very easy but surprisingly it does not work! That action is completely skipped. I think the problem is caused by that huge amount of "if statements".
This is my code: (the part that is skipped is in the 2nd piece of code)
-(void)setCustomUsername{
stillChecking = YES;
ACAccountStore *account = [[ACAccountStore alloc] init];
ACAccountType *accountType = [account accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
[account requestAccessToAccountsWithType:accountType withCompletionHandler:^(BOOL granted, NSError *error)
{
// Did user allow us access?
if (granted == YES)
{
// Populate array with all available Twitter accounts
arrayOfAccounts = [account accountsWithAccountType:accountType];
// Sanity check
if ([arrayOfAccounts count] > 0)
{
NSString *customUser = [self updateCustomUser];
int numberOfAccounts = [arrayOfAccounts count];
int accountsAdded = 0;
specAccountIndex = 0;
NSLog(#"index 0 = %#", [[arrayOfAccounts objectAtIndex:0] username]);
NSLog(#"index 1 = %#", [[arrayOfAccounts objectAtIndex:1] username]);
NSLog(#"spec_username = %#", customUser);
NSLog(#"numberOfAccounts = %i", numberOfAccounts);
// Check if a specified username exist.
if (isThereASpecifiedUsername) {
NSLog(#"3");
while (numberOfAccounts > accountsAdded) {
NSLog(#"4");
if ([customUser isEqualToString:[[arrayOfAccounts objectAtIndex:specAccountIndex] username]]) {
NSLog(#"NewTweet will use the account at index %i", specAccountIndex);
accountsAdded = numberOfAccounts;
stillChecking = NO;
//[accountIndexLabel setText:[NSString stringWithFormat:#"%i", selAccountIndex]];
}
else{
++specAccountIndex;
++accountsAdded;
}
}
NSLog(#"specAccountIndex: %i", specAccountIndex);
}
else {
---------------------------THIS IS THE IMPORTANT PART (BELOW)----------------------------
//we set the value of a simple integer to 0
specAccountIndex = 0;
//now we set the string "finalChoice" equal to specAccountIndex
NSString *finalChoice = [NSString stringWithFormat:#"%i", specAccountIndex];
//now just a check (and yes, it works)
NSLog(#"The app will use the account at index %#", finalChoice);
//than we set the text of a label equal to finalChoice (This part does *NOT* work)
[accountIndexLabel setText:finalChoice];
//than we check if the text has been set (This part does *NOT* work)
NSLog(#"accountIndexLabel check = %#", accountIndexLabel.text);
stillChecking = NO;
}
}}}];
while (stillChecking) {}
NSLog(#"accountIndexLabel check at the end of the process = %#", accountIndexLabel.text);
}
As found out in the comments by Paul, your accountIndexLabel is nil. I suppose this is because you forgot to drag a line from the UILabel to the outlet in the owner's code or forgot to add the outlet before your UILabel field OR if you initialize your UILabel in code that you forgot to alloc init it.
Setting a NSString onto a nil object won't raise an exception in Objective-C as it would do in other languages, in fact it's calling a setter on a nil object which is calling a method on a nil object which just does nothing in Objective-C.
Vote up Pauls comment :-)